diff --git a/112. Path Sum.md b/112. Path Sum.md new file mode 100644 index 0000000..2bd785d --- /dev/null +++ b/112. Path Sum.md @@ -0,0 +1,188 @@ +# step 1 + +再帰なしDFS + +ノードの数をnとして、 +- time complexity: O(n) +- space complexity: O(n) +```python +class Solution: + def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: + if root is None: + return False + + stack = [(root, root.val)] + while stack: + node, sum_so_far = stack.pop() + if ( + node.left is None + and node.right is None + and sum_so_far == targetSum + ): + return True + if node.left is not None: + stack.append((node.left, sum_so_far + node.left.val)) + if node.right is not None: + stack.append((node.right, sum_so_far + node.right.val)) + return False +``` + +再帰なしDFS(None比較を中に持ってくる)。一つ前に書いたものの方が好みだった。以下の解法だと、stackからpopした段階で、sum_so_farはnodeの値を除くこれまでのpathの総和となっていて少し複雑に感じた。 +- time complexity: O(n) +- space complexity: O(n) +```python +class Solution: + def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: + stack = [(root, 0)] + while stack: + node, sum_so_far = stack.pop() + if node is None: + continue + sum_so_far += node.val + if ( + node.left is None + and node.right is None + and sum_so_far == targetSum + ): + return True + stack.append((node.left, sum_so_far)) + stack.append((node.right, sum_so_far)) + return False +``` + +再帰DFS。木がバランスしていない時に、再帰の深さが最大となり、その際はノードの数と一致する。 +left側で見つかってもright側を調べるようにしてしまった。 +よって再帰の深さの最大は5000。 +- time complexity: O(n) +- space complexity: O(n) (積んでいくスタックのサイズがO(n)となる) +```python +class Solution: + def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: + if root is None: + return False + + def has_path_sum_helper( + node: Optional[TreeNode], + sum_so_far: int + ) -> bool: + if ( + node.left is None + and node.right is None + and sum_so_far == targetSum + ): + return True + + left_path = False + if node.left is not None: + left_path = has_path_sum_helper( + node.left, + sum_so_far + node.left.val + ) + right_path = False + if node.right is not None: + right_path = has_path_sum_helper( + node.right, + sum_so_far + node.right.val + ) + return left_path or right_path + + return has_path_sum_helper(root, root.val) +``` + +# step 2 +- https://github.com/colorbox/leetcode/pull/39/files + - stackの変数名がstackではなくnodes_and_sums + - c++だと型名にstackが入るのでわかりやすい + - 自分のコードはstackの初期化の2行下で、`node, sum_so_far = stack.pop()`としているので、 + 何が入ってるか許容範囲内だとは思う。 +- https://github.com/olsen-blue/Arai60/pull/25/files + - ヘルパー関数付きのDFS。これまでのpathの和から今注目しているnodeの値を除いたものを引数としていた + - 自分が思っていたよりは複雑さがなかった。 + - leftでpathが見つかればすぐにTrueを返すようになっていた +- https://github.com/hroc135/leetcode/pull/24/files#r1806608721 + - 短絡評価 + - できていなかった +- https://github.com/hayashi-ay/leetcode/pull/30/files + - targetSumから引いていくようにすれば、helperなしでも再帰でかける + +targetSumを引いていきながら、そのまま再帰 +```python +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 root.val == targetSum + return ( + self.hasPathSum(root.left, targetSum - root.val) + or self.hasPathSum(root.right, targetSum - root.val) + ) +``` + +Noneぶっ込み、短絡評価 +```python +class Solution: + def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: + def has_path_sum_helper( + node: Optional[TreeNode], + sum_so_far: int + ) -> bool: + if node is None: + return False + sum_so_far += node.val + if node.left is None and node.right is None: + return sum_so_far == targetSum + return ( + has_path_sum_helper(node.left, sum_so_far) + or has_path_sum_helper(node.right, sum_so_far) + ) + + return has_path_sum_helper(root, 0) +``` + +Noneぶっ込み、stack使用解法 +```python +class Solution: + def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: + nodes_and_sums = [(root, 0)] + while nodes_and_sums: + node, sum_so_far = nodes_and_sums.pop() + if node is None: + continue + sum_so_far += node.val + if node.left is None and node.right is None: + if sum_so_far == targetSum: + return True + continue + nodes_and_sums.append((node.left, sum_so_far)) + nodes_and_sums.append((node.right, sum_so_far)) + return False +``` + +# step 3 + +結局,sum_so_farという値が自分の中で一番整合性のとれている再帰を使わない解法を書いた。 + +```python +class Solution: + def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: + if root is None: + return False + + nodes_and_sums = [(root, root.val)] + while nodes_and_sums: + node, sum_so_far = nodes_and_sums.pop() + if ( + node.left is None + and node.right is None + and sum_so_far == targetSum + ): + return True + if node.left is not None: + nodes_and_sums.append((node.left, sum_so_far + node.left.val)) + if node.right is not None: + nodes_and_sums.append((node.right, sum_so_far + node.right.val)) + return False +``` + +雑な感想)成長かはわからないが、プログラムの中で空行を入れる箇所が減った気がする。 \ No newline at end of file