-
Notifications
You must be signed in to change notification settings - Fork 0
112. Path Sum #31
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
base: main
Are you sure you want to change the base?
112. Path Sum #31
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,139 @@ | ||
| ### Step1 | ||
|
|
||
| - 本当は部下に仕事を任せてreturnしてもらう実装が好きだが、値の候補がたくさんreturnされてしまうのがどうかと思い、backtrackingで書いた | ||
| - nonlocalでもいいが、mutableなリストで書いた | ||
|
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. nonlocalの方が意図が明確だと思います。 |
||
| - 最初、子供がいるかは判定せずに、if not node: の時にtargetと照合しようとして失敗。片方しか子供がいない時にも判定されてしまう。 | ||
| - このbacktrackingのアルゴリズムをリファクタリンぎしたやつをStep2の最後に記載 | ||
|
|
||
| ```python | ||
|
|
||
| class Solution: | ||
| 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): | ||
|
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 sum_so_far == targetSum: | ||
| has_target[0] = True | ||
|
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したら良いでしょう。 |
||
| if node.left: | ||
| search_target_sum(sum_so_far, node.left) | ||
| if node.right: | ||
| search_target_sum(sum_so_far, node.right) | ||
| sum_so_far -= node.val | ||
|
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. 不要でしょう。 |
||
|
|
||
| if not root: | ||
| return False | ||
| has_target = [False] | ||
| search_target_sum(0, root) | ||
| return has_target[0] | ||
| ``` | ||
|
|
||
| ### Step2 | ||
| - [参考] | ||
| - (https://github.com/TORUS0818/leetcode/pull/27/files) | ||
| - (https://github.com/kazukiii/leetcode/pull/26/files) | ||
| - 再帰をするなら、単にFalse, Trueを返す関数を作ればよかった。(なぜか変にsumを全部返さなきゃとか思ってしまった) | ||
|
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. Step 1でも、sumは返していないようです。 |
||
| - 下でこれをさらにリファクタしてます | ||
|
|
||
| ```python | ||
|
|
||
| class Solution: | ||
| 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): | ||
| return sum_so_far == targetSum | ||
| if node.left and search_target_sum(sum_so_far, node.left): | ||
| return True | ||
| if node.right and search_target_sum(sum_so_far, node.right): | ||
| return True | ||
| return False | ||
|
|
||
| if not root: | ||
|
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. search_target_sumの中に入れたほうが、コードの重複が減りますね。 |
||
| return False | ||
| return search_target_sum(0, root) | ||
| ``` | ||
|
|
||
| - if not node: でreturn Falseすればいいのか〜 | ||
| - なんか、葉であるのとnodeがそもそもないのを両方関数内で判定すると言う発想がなかった | ||
| - こう言うのは最後のないところまで探索するのがいいね | ||
|
|
||
| ```python | ||
|
|
||
| class Solution: | ||
| def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: | ||
| def search_target_sum(sum_so_far, node: Optional[TreeNode]): | ||
| if not node: | ||
| return False | ||
| sum_so_far += node.val | ||
| if not (node.left or node.right): | ||
| 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) | ||
|
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コードでスコープ外の変数を使っている人を見かけるのですが、これってPythonでは一般的なんでしょうか?
Owner
Author
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. 「スコープ外の変数を使う」とは今回の場合、69行目において、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. 特に問題ないと思います。 |
||
| ``` | ||
|
|
||
| - 手でやるならbacktrackingのように足し引きしながら計算する気がするので、Step1を綺麗にしたやつを書いてみる | ||
| - [True]みたいに要素数1のリストを持たせるのも微妙かと思い、path_sumsをsetで持たせることにした | ||
|
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に()をつけるか迷った(つけないと分かりにくいか、不要か) | ||
|
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. 不要でしょう。 |
||
|
|
||
| ```python | ||
|
|
||
| class Solution: | ||
| def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: | ||
| def caluculate_path_sums(sum_so_far, node: Optional[TreeNode], path_sums: set): | ||
|
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. path_sumsを引数として渡す必要はなさそうです。 |
||
| if not node: | ||
| return | ||
| sum_so_far += node.val | ||
| if not node.left and not node.right: | ||
| 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 | ||
|
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.
Owner
Author
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. 手作業でbacktrackingするなら戻る時に引くなあと思って入れたんですが、よく考えたら引いた後に関数内でなんか操作している訳ではないのでいらなかったですね。 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. sum_so_farをcall stackに積まないで、nonlocalとして扱う書き方もありますね。その場合は、一歩戻るときに
Owner
Author
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. 確かに、自分が頭でシミュレーションしてたのをコードに書くならそれになりますね。 |
||
|
|
||
| path_sums = set() | ||
| caluculate_path_sums(0, root, path_sums) | ||
| return (targetSum in path_sums) | ||
| ``` | ||
|
|
||
| ## Step3(レビュー反映復習) | ||
| ```python | ||
|
|
||
| class Solution: | ||
|
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. l62の方が良かったと思います。
Owner
Author
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. 確かに自分もどれを選ぶかを選ぶならl62のやつで書くかもです。(今回はStep1の書き直しという感じで書いてみました) |
||
| def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: | ||
| def search_target_sum(sum_so_far, node: Optional[TreeNode]): | ||
| nonlocal has_target | ||
| if not node: | ||
| return | ||
|
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 has_target: return
Owner
Author
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. あ、書いた時頭が混乱していましたが、これはL111のreturnとは別で、探索をかなりスルーできますね。(逆にL111はその後すぐNoneのノードが来るのでreturnする意味そんなにないですね) |
||
| sum_so_far += node.val | ||
| if not node.left and not node.right: | ||
| if sum_so_far == targetSum: | ||
| has_target = True | ||
| return | ||
| search_target_sum(sum_so_far, node.left) | ||
| search_target_sum(sum_so_far, node.right) | ||
|
|
||
| has_target = False | ||
| search_target_sum(0, root) | ||
| return has_target | ||
| ``` | ||
|
|
||
| - こうは書かないけど一応 | ||
|
|
||
| ```python | ||
| python | ||
| class Solution: | ||
| def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: | ||
| def calculate_path_sums(node, sum_so_far): | ||
| if not node: | ||
| return | ||
| sum_so_far += node.val | ||
| if not node.left and not node.right: | ||
| path_sums.add(sum_so_far) | ||
| calculate_path_sums(node.left, sum_so_far) | ||
| calculate_path_sums(node.right, sum_so_far) | ||
|
|
||
| path_sums = set() | ||
| calculate_path_sums(root, 0) | ||
| return targetSum in path_sums | ||
|
|
||
| ``` | ||
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.
答えを一つ見つけたら、そこで打ち切った方が良いでしょう。