diff --git a/problems/112.path-sum/memo.md b/problems/112.path-sum/memo.md new file mode 100644 index 0000000..30ae75b --- /dev/null +++ b/problems/112.path-sum/memo.md @@ -0,0 +1,32 @@ +## step1 +- 幅優先探索みたいなのしたらできそう +- Node.valにマイナスが入る場合があるので超えたら終わりみたいなことはできなさそう +- 元のNodeのvalを書き換えるとまずいので、累積の値を管理するものを作る必要がありそう +- 途中で切ってもいいのかと思っていたが最後の子まで行かないとだめだった + +## step2 +- 時間計算量、空間計算量はO(N)だと思う +- 他の人のコードを見る前に他にやり方がないか考える + - 取りたくない選択肢だが元のNodeのvalを累積値に書き換えるorTreeNodeに新しいメンバ変数を持たせる + - やっていることは同じだが、再帰でも同様のことができそう? + - 一旦書いてみる + - root is NoneでtargetSum == 0を最終的な条件にしようとしたが、初期条件のrootがNoneでtargetSumが0の場合はFalseにしたいのでhelperを作った + - 中々うまくかけず、試行錯誤して最終的にChatGPTに聞いてしまった +- 他の人のコードを見る +- https://github.com/05ryt31/leetcode/pull/16/files + - 自分としては少し気をつけたところだが、Trueが見つかった場合に打ち切ってくれるかどうかの観点はあった方が良いと思った +- https://github.com/mamo3gr/arai60/pull/24 + - https://github.com/mamo3gr/arai60/pull/24/files#r2678467960 + - 再帰とキューの比較 + - 書いている際に条件は確認したがスタックにどのくらい積まれるかは毎回忘れずにmemoでも言及したいと思った + - `is_leaf`と変数にするのは情報が増えていいと思った +- https://github.com/naoto-iwase/leetcode/pull/29 + - `もし葉でtargetSumになるような経路を返却するとしたらどうでしょうか?設問としてはTrue/Falseなのですが、単純にTrue/Falseを得るよりはpathを実際に知るほうが意味があるのかなと思ったので...自分が面接だったら質問しそうです。` + follow-upの質問があったので考えると、累積を加えて渡すのと同様に通ってきたNodeのlistをtupleに足して管理するようにしそうだが、毎回Listをcopyしないと壊れそうで結構重い処理になりそう + `そうですね、通ったノードのその時点の和を記録するsetまたは辞書を持つようにし、ゴールの葉からスタートに向かって再びBFS/DFSするのが(空間)計算量が節約できて良さそうですね。さらに、そのようなpathの総数/pathを全部知りたい場合は、1回目の前向きの探索をearly returnなしで完遂し、和の記録も通った回数を辞書で記録しておくのが良さそうに思います。`この解法は思いつかなかったが和を記録したとして親を辿る方法が和が一致する物の中から子を見て一致したら親のNodeと判定しないといけないような気がするので大変だと思った +- 自分で再帰でも書けそうだと思った部分は進歩だと思うが、やはりすんなり書けないのでもっと練習が必要だと思った + +## step3 +- `is_leaf`を使って書くように修正した +- step1と違いやるべきことが明確に頭の中にあったので5分ほどでかけた + diff --git a/problems/112.path-sum/step1.py b/problems/112.path-sum/step1.py new file mode 100644 index 0000000..e6fa3ea --- /dev/null +++ b/problems/112.path-sum/step1.py @@ -0,0 +1,41 @@ +# +# @lc app=leetcode id=112 lang=python3 +# +# [112] Path Sum +# + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +import collections + + +class Solution: + def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: + if root is None: + return False + accumulate = root.val + frontier = collections.deque() + frontier.append((root, accumulate)) + + while frontier: + frontier_node, accumulate = frontier.popleft() + if frontier_node.left is None and frontier_node.right is None: + if accumulate == targetSum: + return True + if frontier_node.left is not None: + next_accumulate = accumulate + frontier_node.left.val + frontier.append((frontier_node.left, next_accumulate)) + + if frontier_node.right is not None: + next_accumulate = accumulate + frontier_node.right.val + frontier.append((frontier_node.right, next_accumulate)) + + return False + + +# @lc code=end diff --git a/problems/112.path-sum/step2.py b/problems/112.path-sum/step2.py new file mode 100644 index 0000000..1c2226c --- /dev/null +++ b/problems/112.path-sum/step2.py @@ -0,0 +1,27 @@ +# +# @lc app=leetcode id=112 lang=python3 +# +# [112] Path Sum +# + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: + if root is None: + return False + + if root.left is None and root.right is None: + return targetSum == root.val + + return self.hasPathSum(root.left, targetSum - root.val) or self.hasPathSum( + root.right, targetSum - root.val + ) + + +# @lc code=end diff --git a/problems/112.path-sum/step3.py b/problems/112.path-sum/step3.py new file mode 100644 index 0000000..3c9461e --- /dev/null +++ b/problems/112.path-sum/step3.py @@ -0,0 +1,43 @@ +# +# @lc app=leetcode id=112 lang=python3 +# +# [112] Path Sum +# + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +import collections + + +class Solution: + def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: + if root is None: + return False + total_val = root.val + + frontier = collections.deque() + frontier.append((root, total_val)) + + while frontier: + frontier_node, val = frontier.popleft() + + is_leaf = frontier_node.left is None and frontier_node.right is None + + if is_leaf and val == targetSum: + return True + + if frontier_node.left: + frontier.append((frontier_node.left, val + frontier_node.left.val)) + + if frontier_node.right: + frontier.append((frontier_node.right, val + frontier_node.right.val)) + + return False + + +# @lc code=end