-
Notifications
You must be signed in to change notification settings - Fork 0
617. Merge Two Trees #30
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?
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 @@ | ||
### Step1 | ||
|
||
- nodeがNoneの時も合わせて処理を一般化するために関数を作ったけど、ここまでする必要はなかったかも | ||
- returnする値が多くて見にくい気も | ||
- このときはdeepcopyしてrootをreturnする選択肢に気づいていない | ||
- merged_rootとmerged_nodeで変数名を迷う(再帰をしていく中でこの変数はrootでなくなるので) | ||
|
||
```python | ||
|
||
class Solution: | ||
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: | ||
# node.valと、node.leftと、node.rightについて、nodeがNoneの場合でも共通して処理できるようにする | ||
def process_node_when_not_existing(node): | ||
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. Noneをチェックするだけなので、processという動詞と合っていないように思いました。 |
||
node_val = node.val if node else 0 | ||
node_left = node.left if node else None | ||
node_right = node.right if node else None | ||
return node_val, node_left, node_right | ||
Comment on lines
+14
to
+17
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. 何度もinline ifを使っているのが気になります。
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 root1 and not root2: | ||
return None | ||
root1_val, root1_left, root1_right = process_node_when_not_existing(root1) | ||
root2_val, root2_left, root2_right = process_node_when_not_existing(root2) | ||
merged_node = TreeNode(root1_val + root2_val) | ||
merged_node.left = self.mergeTrees(root1_left, root2_left) | ||
merged_node.right = self.mergeTrees(root1_right, root2_right) | ||
return merged_node | ||
``` | ||
|
||
### Step2 | ||
|
||
- 参考資料 | ||
|
||
https://github.com/TORUS0818/leetcode/pull/25 | ||
|
||
- どちらかなくなったらもう一方をそのまま返せば良いと言うことになぜか気づかなかった… | ||
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. 最初からこれに気づくのは難しいですね。 |
||
- 非破壊的にしたければdeepcopy()か | ||
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. インプットのツリーは参照されているものの、破壊はされていないです。https://en.wikipedia.org/wiki/Copy-on-write 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. これ、root1とかが後で変更されると、すでに実行した関数の返り値も変更されてしまうということだったんですね。 |
||
- 再帰を使わない手もある | ||
- https://discord.com/channels/1084280443945353267/1201211204547383386/1218151037697917028 | ||
- https://github.com/kazukiii/leetcode/pull/24/files | ||
- https://discord.com/channels/1084280443945353267/1201211204547383386/1217821129297629364 | ||
- 部下から返ってきたときに、それを紐づける仕事をどこでやるか | ||
- 部下に仕事を押し付けない再帰 | ||
- 上のStep1のやつ | ||
- 部下に仕事を押し付ける(書き込んでしまう)再帰 | ||
- 部下に仕事を渡す前に、自分の上司との処理をしてしまう | ||
- Step1より、下のようにダミーのnodeを作るのが賢いと気づいた(しかもこれなら入力も変更されない) | ||
|
||
```python | ||
|
||
from copy import deepcopy | ||
|
||
class Solution: | ||
def make_dummy_node_when_none(self, node): | ||
if node: | ||
return node | ||
dummy = TreeNode(0) | ||
dummy.left = None | ||
dummy.right = None | ||
return dummy | ||
|
||
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: | ||
def merge_helper(node1, node2, merged): | ||
if not(node1.left or node2.left or node1.right or node2.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. 細かいですがkeywordであるnotが関数のように見えるのでnotと()の間は空白を入れた方が良い気がします。 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. ありがとうございます。 |
||
return | ||
if node1.left or node2.left: | ||
node1_left = self.make_dummy_node_when_none(node1.left) | ||
node2_left = self.make_dummy_node_when_none(node2.left) | ||
merged.left = TreeNode(node1_left.val + node2_left.val) | ||
merge_helper(node1_left, node2_left, merged.left) | ||
if node1.right or node2.right: | ||
node1_right = self.make_dummy_node_when_none(node1.right) | ||
node2_right = self.make_dummy_node_when_none(node2.right) | ||
merged.right = TreeNode(node1_right.val + node2_right.val) | ||
merge_helper(node1_right, node2_right, merged.right) | ||
Comment on lines
+65
to
+74
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. deepcopyが使えそうですか。
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 root1: | ||
return deepcopy(root2) | ||
if not root2: | ||
return deepcopy(root1) | ||
merged_root = TreeNode(root1.val + root2.val) | ||
merge_helper(root1, root2, merged_root) | ||
return merged_root | ||
``` | ||
|
||
- 部下に仕事を押し付けないstack | ||
- [参考](https://discord.com/channels/1084280443945353267/1227073733844406343/1236682759649497099) | ||
- [これ](https://discord.com/channels/1084280443945353267/1227073733844406343/1236324993839792149)でもいいが、あえて練習のためis_goingのフラグをつけた | ||
- liquo_riceさんの最初でpopせず帰りにpopする実装と、行き帰りのフラグをつける実装だと、よく考えたら探索順も異なる | ||
- 以下実装時のメモ(フラグがあるバージョン) | ||
- 帰りの時に行うのは、取り出したmerged_nodeに対してleftのmerged_nodeとrightのmerged_nodeをくっつける | ||
- よって、引き継ぎで必要な情報は、今のmerged_nodeと、leftのmerged_nodeと、rightのmerged_node。(行きには現在のnodeが必要) | ||
- appendする時には、mutableなlistにしてbackのmerged_leftとgoのcurrent_merged(=次に取り出されるbackのmerge)が同じものを指すようにする | ||
- listがその要素への参照なので、1要素のlistがCとかの参照の代わりになるというの、確かに | ||
- めっちゃ時間かかった、以前1回実装を読んだつもりだったが、ちゃんと理解できてなかったことが判明、、、 | ||
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 でのこれは半分概念の説明のためのもので実用性はあまりないですね。 |
||
|
||
```python | ||
|
||
from copy import deepcopy | ||
|
||
class Solution: | ||
def make_dummy_node_when_none(self, node): | ||
if node: | ||
return node | ||
dummy = TreeNode(0) | ||
dummy.left = None | ||
dummy.right = None | ||
return dummy | ||
|
||
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: | ||
if not root1: | ||
return deepcopy(root2) | ||
if not root2: | ||
return deepcopy(root1) | ||
merged_root = [None] | ||
nodes_stack = [(root1, root2, merged_root, [None], [None], "go")] | ||
while nodes_stack: | ||
node1, node2, merged_current, merged_left, merged_right, go_or_back = nodes_stack.pop() | ||
if go_or_back == "go": | ||
nodes_stack.append((node1, node2, merged_current, merged_left, merged_right, "back")) | ||
if node1.left or node2.left: | ||
node1_left = self.make_dummy_node_when_none(node1.left) | ||
node2_left = self.make_dummy_node_when_none(node2.left) | ||
nodes_stack.append((node1_left, node2_left, merged_left, [None], [None], "go")) | ||
if node1.right or node2.right: | ||
node1_right = self.make_dummy_node_when_none(node1.right) | ||
node2_right = self.make_dummy_node_when_none(node2.right) | ||
nodes_stack.append((node1_right, node2_right, merged_right, [None], [None], "go")) | ||
else: | ||
merged_current[0] = TreeNode(node1.val + node2.val) | ||
merged_current[0].left = merged_left[0] | ||
merged_current[0].right = merged_right[0] | ||
return merged_root[0] | ||
``` | ||
|
||
- 部下に仕事を押し付けるstack | ||
|
||
```python | ||
|
||
from copy import deepcopy | ||
|
||
class Solution: | ||
def make_dummy_node_when_none(self, node): | ||
if node: | ||
return node | ||
dummy = TreeNode(0) | ||
dummy.left = None | ||
dummy.right = None | ||
return dummy | ||
|
||
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: | ||
if not root1: | ||
return deepcopy(root2) | ||
if not root2: | ||
return deepcopy(root1) | ||
merged_root = TreeNode(root1.val + root2.val) | ||
nodes_stack = [(root1, root2, merged_root)] | ||
while nodes_stack: | ||
node1, node2, merged_node = nodes_stack.pop() | ||
if node1.left or node2.left: | ||
node1_left = self.make_dummy_node_when_none(node1.left) | ||
node2_left = self.make_dummy_node_when_none(node2.left) | ||
merged_node.left = TreeNode(node1_left.val + node2_left.val) | ||
nodes_stack.append((node1_left, node2_left, merged_node.left)) | ||
if node1.right or node2.right: | ||
node1_right = self.make_dummy_node_when_none(node1.right) | ||
node2_right = self.make_dummy_node_when_none(node2.right) | ||
merged_node.right = TreeNode(node1_right.val + node2_right.val) | ||
nodes_stack.append((node1_right, node2_right, merged_node.right)) | ||
return merged_root | ||
``` | ||
|
||
### Step3 | ||
|
||
```python | ||
|
||
from copy import deepcopy | ||
|
||
class Solution: | ||
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: | ||
if not root1: | ||
return deepcopy(root2) | ||
if not root2: | ||
return deepcopy(root1) | ||
merged_root = TreeNode(root1.val + root2.val) | ||
merged_root.left = self.mergeTrees(root1.left, root2.left) | ||
merged_root.right = self.mergeTrees(root1.right, root2.right) | ||
return merged_root | ||
``` |
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.
これ確かに自分抜けがちです。ありがとうございます