-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add 112. Path Sum.md #25
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
): | ||
Comment on lines
+17
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 個人的な好みですが下記のような書き方のほうが読みやすいと思いました、条件部分がカッコ含めてひとかたまりになっていてわかりやすいためです。 if (node.left is None
and node.right is None
and sum_so_far == targetSum): There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. そうしていない理由としては、最後の条件(今回で言うと |
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return sum_so_far == targetSumという手もございます🙇 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. step2で実装済みでした。失礼しました。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 付け加えると、このコードでそれをやってしまうと適当な葉ノードにたどり着いた段階で探索が終わってしまいます。 if node.left is None and node.right is None:
if sum_so_far == targetSum:
return True
continue |
||
): | ||
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: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 好みの問題かもしれませんが、カッコ内の改行が多いと読みにくく感じます。2引数程度であれば1行で書いてしまっていいと思います。 |
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
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を引いていきながら、そのまま再帰 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 好みですが、私は 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. スタックに空ノードが入ることを許容する方法のメリットはループ内の条件分岐が減ることにあると思うので、私は単に if node.left is None and node.right is None and sum_so_far == targetSum:
return True とします。 |
||
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 | ||
``` | ||
|
||
雑な感想)成長かはわからないが、プログラムの中で空行を入れる箇所が減った気がする。 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 成長かと思います。 それはそうと、複数行の文の改行の入れ方、フォーマッターに一度かけてみるといいかもしれません。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. フォーマッターというとblackとかですかね。使って変化を見てみます。 あと、少し話がそれますが、leetcodeだとtype annotationが全体的に古いことが気になります。leetcodeでのpython3のバージョンは3.11みたいなので(https://support.leetcode.com/hc/en-us/articles/360011833974-What-are-the-environments-for-the-programming-languages)、[List](https://docs.python.org/3/library/typing.html#typing.List)とかdeprecatedなように思います。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. これわかる気がします。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 私もなぜか空行が減りました。以前はコードの可読性を高める手段として変数名の工夫と空行を挟むことくらいしか持ち合わせていなかったのでそうしていたような気がします。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. コードを読む機会が増えて空行がないコードを読むことが苦にならなくなったのもあると思います。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
単純にsumでも良いと思いました。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sum は Python では予約語のため、避けたほうがよいと思います。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
失礼いたしました。きちんと調べないとですね。誤ったコメントすみません。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(細かいのと、いろいろな方言があるのですが、予約語は keyword、builtin は組み込みと対応させることが多く、sum は builtin のほうです。)
https://docs.python.org/ja/3/reference/lexical_analysis.html#keywords
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
失礼いたしました。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
私は、sum は被るので total にしていました。