Skip to content

Conversation

@nittoco
Copy link
Owner

@nittoco nittoco commented Jul 30, 2024

https://leetcode.com/problems/path-sum/description/
Given the root of a binary tree and an integer targetSum, return true if the tree has a root-to-leaf path such that adding up all the values along the path equals targetSum.

A leaf is a node with no children.

https://leetcode.com/problems/path-sum/description/
Given the root of a binary tree and an integer targetSum, return true if the tree has a root-to-leaf path such that adding up all the values along the path equals targetSum.

A leaf is a node with no children.
search_target_sum(sum_so_far, node.left)
if node.right:
search_target_sum(sum_so_far, node.right)
sum_so_far -= node.val

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sum_so_far -= node.valこれ必要でしょうか。

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不要でしょう。

path_sums.add(sum_so_far)
caluculate_path_sums(sum_so_far, node.left, path_sums)
caluculate_path_sums(sum_so_far, node.right, path_sums)
sum_so_far -= node.val

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sum_so_far -= node.valこれ必要でしょうか。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

手作業でbacktrackingするなら戻る時に引くなあと思って入れたんですが、よく考えたら引いた後に関数内でなんか操作している訳ではないのでいらなかったですね。
Pythonでは変数はその関数内でローカルなので、関数抜けたら戻りますし。
ありがとうございます。

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sum_so_farをcall stackに積まないで、nonlocalとして扱う書き方もありますね。その場合は、一歩戻るときに sum_so_far -= node.val を入れてあげないとですね。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

確かに、自分が頭でシミュレーションしてたのをコードに書くならそれになりますね。
スッキリしました、ありがとうございます。

```

- 手でやるならbacktrackingのように足し引きしながら計算する気がするので、Step1を綺麗にしたやつを書いてみる
- [True]みたいに要素数1のリストを持たせるのも微妙かと思い、path_sumsをsetで持たせることにした

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

全ての根から葉までの和を保持しておくのはやや贅沢な気がします。
少し設定を変えてtargetSumに合致するようなパスがいくつあるか数える時、とかならこういう実装も良さそうですね。


- 手でやるならbacktrackingのように足し引きしながら計算する気がするので、Step1を綺麗にしたやつを書いてみる
- [True]みたいに要素数1のリストを持たせるのも微妙かと思い、path_sumsをsetで持たせることにした
- returnに()をつけるか迷った(つけないと分かりにくいか、不要か)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

個人的には不要かなと思いました。分かりやすくなっていない気がするので。

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不要でしょう。

return sum_so_far == targetSum
return search_target_sum(sum_so_far, node.left) or search_target_sum(sum_so_far, node.right)

return search_target_sum(0, root)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここにtargetSumを渡して、関数内で引いていく方式にすればスコープ外の変数を使わなくて済むのでそれも手だと思います

付随した質問: よくPythonコードでスコープ外の変数を使っている人を見かけるのですが、これってPythonでは一般的なんでしょうか?
個人的には変数のスコープは明確であってほしいと思ってしまいます

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

「スコープ外の変数を使う」とは今回の場合、69行目において、targetSumが外側にある、ということですよね。それをしたくない理由は、挙動が追いにくいからでしょうか。(言われれば確かにそう感じる理由もわかる気がします)
自分は大規模コードの開発経験がないのでいまいち一般的な感覚がわからないのですが、どうなんでしょう…?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

特に問題ないと思います。

### Step1

- 本当は部下に仕事を任せてreturnしてもらう実装が好きだが、値の候補がたくさんreturnされてしまうのがどうかと思い、backtrackingで書いた
- nonlocalでもいいが、mutableなリストで書いた

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nonlocalの方が意図が明確だと思います。

search_target_sum(sum_so_far, node.left)
if node.right:
search_target_sum(sum_so_far, node.right)
sum_so_far -= node.val

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不要でしょう。

def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
def search_target_sum(sum_so_far, node: Optional[TreeNode]):
sum_so_far += node.val
if not (node.left or node.right):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not node.left and not node.rightの方がわかりやすく感じます。

sum_so_far += node.val
if not (node.left or node.right):
if sum_so_far == targetSum:
has_target[0] = True

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここでreturnしたら良いでしょう。

@@ -0,0 +1,96 @@
### Step1

- 本当は部下に仕事を任せてreturnしてもらう実装が好きだが、値の候補がたくさんreturnされてしまうのがどうかと思い、backtrackingで書いた

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

答えを一つ見つけたら、そこで打ち切った方が良いでしょう。

- [参考]
- (https://github.com/TORUS0818/leetcode/pull/27/files)
- (https://github.com/kazukiii/leetcode/pull/26/files)
- 再帰をするなら、単にFalse, Trueを返す関数を作ればよかった。(なぜか変にsumを全部返さなきゃとか思ってしまった)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Step 1でも、sumは返していないようです。

return True
return False

if not root:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

search_target_sumの中に入れたほうが、コードの重複が減りますね。

return sum_so_far == targetSum
return search_target_sum(sum_so_far, node.left) or search_target_sum(sum_so_far, node.right)

return search_target_sum(0, root)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

特に問題ないと思います。


- 手でやるならbacktrackingのように足し引きしながら計算する気がするので、Step1を綺麗にしたやつを書いてみる
- [True]みたいに要素数1のリストを持たせるのも微妙かと思い、path_sumsをsetで持たせることにした
- returnに()をつけるか迷った(つけないと分かりにくいか、不要か)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不要でしょう。


class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
def caluculate_path_sums(sum_so_far, node: Optional[TreeNode], path_sums: set):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

path_sumsを引数として渡す必要はなさそうです。

## Step3(レビュー反映復習)
```python

class Solution:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l62の方が良かったと思います。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

確かに自分もどれを選ぶかを選ぶならl62のやつで書くかもです。(今回はStep1の書き直しという感じで書いてみました)
やり直しとかも見てくださりありがとうございます🙇

Copy link

@kazukiii kazukiii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

見ました。コメントのあるところ以外は良さそうに思いました。

path_sums.add(sum_so_far)
caluculate_path_sums(sum_so_far, node.left, path_sums)
caluculate_path_sums(sum_so_far, node.right, path_sums)
sum_so_far -= node.val
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sum_so_farをcall stackに積まないで、nonlocalとして扱う書き方もありますね。その場合は、一歩戻るときに sum_so_far -= node.val を入れてあげないとですね。

def search_target_sum(sum_so_far, node: Optional[TreeNode]):
nonlocal has_target
if not node:
return
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if has_target: return
で枝狩りしておくと、ツリー全体を舐めなくて済みますね。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

あ、書いた時頭が混乱していましたが、これはL111のreturnとは別で、探索をかなりスルーできますね。(逆にL111はその後すぐNoneのノードが来るのでreturnする意味そんなにないですね)
ありがとうございます

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants