https://leetcode.com/problems/convert-doubly-linked-list-to-array-i/
連結リスト(Node: val/prev/next)を先頭から辿って配列に詰めるだけ。prevは使わない(飾り)。
class Solution:
def toArray(self, root: 'Optional[Node]') -> List[int]:
res = []
while root:
res.append(root.val) # 今の箱の値
root = root.next # 次の箱へ移動
return res
学び:
Node はPython標準にない。LeetCodeがエディタ冒頭のコメントで定義を渡してるroot.next = 次の箱、root.next.val = 次の箱の値(ドットで手繰る).next は None → while root: で終端判定https://leetcode.com/problems/bitwise-or-of-adjacent-elements/
隣同士をビットOR(|)でつないで長さn-1の配列を返す。
class Solution:
def orArray(self, nums: List[int]) -> List[int]:
ans = []
for i in range(len(nums)-1):
ans.append(nums[i] | nums[i+1])
return ans
学び:
|(パイプ)。論理OR = or は別物8 | 4 = 12:ビットで 1000 | 0100 = 1100。各桁どちらかが1なら1return [nums[i] | nums[i+1] for i in range(len(nums)-1)]https://leetcode.com/problems/final-value-of-variable-after-performing-operations/
X=0から操作文字列を順に適用して最終値を返す。++X/X++は+1、--X/X--は-1。
class Solution:
def finalValueAfterOperations(self, operations: list[str]) -> int:
ans = 0
for o in operations:
if "+" in o:
ans += 1
else:
ans -= 1
return ans
学び:
"+" in o で+1/-1の2種類に畳むのが賢い。全文字列比較より簡潔sum(1 if "+" in o else -1 for o in operations))だがforの方が読みやすいhttps://leetcode.com/problems/find-minimum-operations-to-make-all-elements-divisible-by-three/
±1操作で全要素を3の倍数にする最小回数。自力では解けなかった(whileの条件を逆にしてしまった)。
正解:
class Solution:
def minimumOperations(self, nums: List[int]) -> int:
return sum(1 for x in nums if x % 3 != 0)
学び:
sum(min(x%n, n-x%n) for x in nums)https://leetcode.com/problems/build-array-from-permutation/
ans[i] = nums[nums[i]](添字の二段引き)を全iで作る。nums[i]で出た値を、もう一回添字として引く。
提出した版(AC、O(n)時間・O(n)空間):
class Solution:
def buildArray(self, nums: list[int]) -> list[int]:
ans = []
for x in range(len(nums)):
ans.append(nums[nums[x]])
return ans
学び:
nums[x](一段)だとただのコピー。nums[nums[x]](二段)が正解。カッコの重ね方が全て[nums[nums[x]] for x in range(len(nums))] にするとappendが消えて微速。計算量は同じansを作らずnumsに詰め込む)は未着手https://leetcode.com/problems/restore-finishing-order/
完走順 order から、友達 friends のIDだけを完走順で抜き出す。
提出した版(AC、ただし in friends が毎回リスト線形探索でO(n*m)):
class Solution:
def recoverOrder(self, order: List[int], friends: List[int]) -> List[int]:
ans = []
for element in order:
if element in friends:
ans.append(element)
return ans
改善版(friendsをsetにして所属判定O(1)):
class Solution:
def recoverOrder(self, order: List[int], friends: List[int]) -> List[int]:
fs = set(friends)
return [x for x in order if x in fs]
学び:
in)はset」が定石。listのままだと端から線形探索x in fs はlist/setどっちでも動く。違うのは速さだけ(list=O(m)端から探索 / set=O(1)ハッシュ一発)。setじゃなきゃダメなわけではないhttps://leetcode.com/problems/minimum-operations-to-make-array-sum-divisible-by-k/
1回の操作で要素を1減らせる。合計をkで割り切れるようにする最小操作回数。
class Solution:
def minOperations(self, nums: List[int], k: int) -> int:
return sum(nums) % k
学び:
S % k。どの要素を削るかは無関係(合計さえ合えばいい)https://leetcode.com/problems/find-the-degree-of-each-vertex/
隣接行列から各頂点の次数(つながる辺の数)を返す。各行の1の個数=その頂点の次数なので、行の合計を取るだけ。
class Solution:
def findDegrees(self, matrix: list[list[int]]) -> list[int]:
return [sum(row) for row in matrix]
学び:
matrix[i][j]=1 なら頂点 i-j 間に辺あり。i行目の1の総数 = 頂点iの次数sum() で1の個数が出る(合計=カウント)https://leetcode.com/problems/library-late-fee-calculator/
返却遅延日数に応じた罰金の合計。1日→1、2〜5日→2倍、6日以上→3倍。
class Solution:
def lateFee(self, daysLate: List[int]) -> int:
ans = 0
for d in daysLate:
if d == 1:
ans += 1
elif d <= 5:
ans += 2 * d
else:
ans += 3 * d
return ans
学び:
for i in range(len()))より値を直接回す(for d in daysLate)方が読みやすいif d == 1 を抜けた時点で d >= 2 確定 → elif d <= 5 で下限チェック不要return sum(1 if d==1 else 2*d if d<=5 else 3*d for d in daysLate)