ミュータブルなオブジェクトには気をつけよう
LeetCode - 78. Subsetsを解いているときに,エラーの原因がなかなかわからないという状況に陥りました.
問題としては,あるリストの全てのサブリストを要素とするリストをreturnせよという問題です.
class Solution: def subsets(self, nums: List[int]) -> List[List[int]]: ans = [] def dfs(A, limit, index): if len(A) == limit: ans.append(A) else: for i in range(index+1, len(nums)): A.append(nums[i]) dfs(A, limit, i) A.pop() for i in range(len(nums)+1): dfs([], i, -1) return ans
最初,私はこのようなコードを書きました. しかし,[1, 2, 3]を入力としたとき,
input: [1, 2, 3] output: [[], [], [], [], [], [], [], []]
となり,うまくいきませんでした.
なぜ,ansに[ ]しかappendされないのか.
そこで,
class Solution: def subsets(self, nums: List[int]) -> List[List[int]]: ans = [] def dfs(A, limit, index): if len(A) == limit: ans.append(A) print(ans) else: for i in range(index+1, len(nums)): A.append(nums[i]) dfs(A, limit, i) A.pop() for i in range(len(nums)+1): dfs([], i, -1) return ans
とし,ansの動きを見てみると,
[[]] [[], [1]] [[], [2], [2]] [[], [3], [3], [3]] [[], [], [], [], [1, 2]] [[], [], [], [], [1, 3], [1, 3]] [[], [], [], [], [2, 3], [2, 3], [2, 3]] [[], [], [], [], [], [], [], [1, 2, 3]] [[], [], [], [], [], [], [], []]
となっていました. ansの中身のリストAが更新されてしまっている.
ansに毎度idが同じリストAをappendしてしまっており,リストはミュータブルなのでリストAが更新されるたび,ansの中身も更新されてしまっていた.
したがって,
class Solution: def subsets(self, nums: List[int]) -> List[List[int]]: ans = [] def dfs(A, limit, index): if len(A) == limit: ans.append(A[:]) else: for i in range(index+1, len(nums)): A.append(nums[i]) dfs(A, limit, i) A.pop() for i in range(len(nums)+1): dfs([], i, -1) return ans
のようにansにリストAのコピーをappendすればうまくいく.コピーすればidが異なるものとなるからです.
ミュータブルなものを配列に格納するときには,今後注意していこうと思いました.