diff --git a/617-Merge-Two-Binary-Trees/note.md b/617-Merge-Two-Binary-Trees/note.md new file mode 100644 index 0000000..09a671c --- /dev/null +++ b/617-Merge-Two-Binary-Trees/note.md @@ -0,0 +1,43 @@ +# 617. Merge Two Binary Trees + +https://leetcode.com/problems/merge-two-binary-trees/description/ + +## step1(まず通す) + +再帰で書くのがぱっと見わかりやすそうだったのでまずはそれで書く。再帰でスタックする数も高々木の高さなので問題ないはず。 + +## step2(整形&他の人のコードを読む) + +場合によって新しいオブジェクトが作られたり入力が再利用されたりしていて統一感のないコードになってしまった。挙動が一貫していないのは利用者からすると困ると思うので、両極端で書いてみる。 + +入力をインプレースで変更するパターン: step2-1.py + +全ノード再構築するパターン: step2-2.py + +書いてみたが、個人的には一番書きやすく感じられるのは step1.py。そもそも入力が破壊される可能性があるなら気をつけないといけないのは一緒だと思うと、step2-1.py よりは step1.py のほうが良さそうか。 + +とはいえ、自分が使う立場になって一番嬉しいのは step2-2.py だと思う。 + +### 他の人はどう書いているか + +コメント集を見ても、入力を破壊するか否かは重要な論点っぽい。パッと書いてすぐそこを気にすることができたので思考回路としては割と良さそう。 + +- https://github.com/shintaro1993/arai60/pull/27/changes + - 片方が None のときに入力を破壊しないためのやり方にもいくつかあって + - (step2-2.py で私がやっているように)新しく作るノードの子を再帰的に計算する時に、引数の片方を None にする + - 番兵を使う = None を 「値が 0 で、左右の子が None」のノードに置き換えてから root1 も root2 も None でないときと同じ処理をする + - 本質的にはにはどちらも同じことをやっているが、見やすさでいうと後者かな + - 前者の方が宣言的で好きではある +- https://github.com/Fuminiton/LeetCode/pull/23/changes#r1997660222 + - 「一部のノードを共有すると、他の破壊的なメソッドとの相性で残念なことになるかもしれませんね。」 + - step1.py や step2-1.py は単に入力を破壊しているというだけでなくて一部ノードが tree1 と tree2 で共有されてしまう、というのはあまり明示的に意識してなかった。 + +## step3(10分以内にさっとかける \* 3回) + +破壊しないで書く。 + +## step4 + +再帰→スタックの変換。 + +tree1, tree2 の left, right をスタックに詰めた時点で merged_node もデフォルトの TreeNode を受け皿として一緒に詰めておかないと親と子を紐づけられない、というのを理解するのにちょっと時間がかかった。 diff --git a/617-Merge-Two-Binary-Trees/step1.py b/617-Merge-Two-Binary-Trees/step1.py new file mode 100644 index 0000000..ae292e2 --- /dev/null +++ b/617-Merge-Two-Binary-Trees/step1.py @@ -0,0 +1,28 @@ +from typing import Optional + + +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + + +class Solution: + def mergeTrees( + self, root1: Optional[TreeNode], root2: Optional[TreeNode] + ) -> Optional[TreeNode]: + if root1 is None and root2 is None: + return None + + if root1 is None: + return root2 + + if root2 is None: + return root1 + + return TreeNode( + val=root1.val + root2.val, + left=self.mergeTrees(root1.left, root2.left), + right=self.mergeTrees(root1.right, root2.right), + ) diff --git a/617-Merge-Two-Binary-Trees/step2-1.py b/617-Merge-Two-Binary-Trees/step2-1.py new file mode 100644 index 0000000..a318a51 --- /dev/null +++ b/617-Merge-Two-Binary-Trees/step2-1.py @@ -0,0 +1,27 @@ +from typing import Optional + + +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + + +class Solution: + def mergeTrees( + self, root1: Optional[TreeNode], root2: Optional[TreeNode] + ) -> Optional[TreeNode]: + if root1 is None and root2 is None: + return None + + if root1 is None: + return root2 + + if root2 is None: + return root1 + + root1.val += root2.val + root1.left = self.mergeTrees(root1.left, root2.left) + root1.right = self.mergeTrees(root1.right, root2.right) + return root1 diff --git a/617-Merge-Two-Binary-Trees/step2-2.py b/617-Merge-Two-Binary-Trees/step2-2.py new file mode 100644 index 0000000..270f870 --- /dev/null +++ b/617-Merge-Two-Binary-Trees/step2-2.py @@ -0,0 +1,36 @@ +from typing import Optional + + +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + + +class Solution: + def mergeTrees( + self, root1: Optional[TreeNode], root2: Optional[TreeNode] + ) -> Optional[TreeNode]: + if root1 is None and root2 is None: + return None + + if root1 is None: + return TreeNode( + val=root2.val, + left=self.mergeTrees(None, root2.left), + right=self.mergeTrees(None, root2.right), + ) + + if root2 is None: + return TreeNode( + val=root1.val, + left=self.mergeTrees(root1.left, None), + right=self.mergeTrees(root1.right, None), + ) + + return TreeNode( + val=root1.val + root2.val, + left=self.mergeTrees(root1.left, root2.left), + right=self.mergeTrees(root1.right, root2.right), + ) diff --git a/617-Merge-Two-Binary-Trees/step3.py b/617-Merge-Two-Binary-Trees/step3.py new file mode 100644 index 0000000..798eb04 --- /dev/null +++ b/617-Merge-Two-Binary-Trees/step3.py @@ -0,0 +1,27 @@ +from typing import Optional + + +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + + +class Solution: + def mergeTrees( + self, root1: Optional[TreeNode], root2: Optional[TreeNode] + ) -> Optional[TreeNode]: + if root1 is None and root2 is None: + return None + + if root1 is None: + root1 = TreeNode(0) + if root2 is None: + root2 = TreeNode(0) + + return TreeNode( + val=root1.val + root2.val, + left=self.mergeTrees(root1.left, root2.left), + right=self.mergeTrees(root1.right, root2.right), + ) diff --git a/617-Merge-Two-Binary-Trees/step4.py b/617-Merge-Two-Binary-Trees/step4.py new file mode 100644 index 0000000..04cab17 --- /dev/null +++ b/617-Merge-Two-Binary-Trees/step4.py @@ -0,0 +1,35 @@ +from typing import Optional + + +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + + +class Solution: + def mergeTrees( + self, root1: Optional[TreeNode], root2: Optional[TreeNode] + ) -> Optional[TreeNode]: + if root1 is None and root2 is None: + return None + + merged_root = TreeNode() + stack = [(root1, root2, merged_root)] + while stack: + node1, node2, merged_node = stack.pop() + if node1 is None: + node1 = TreeNode(0) + if node2 is None: + node2 = TreeNode(0) + + merged_node.val = node1.val + node2.val + if not (node1.left is None and node2.left is None): + merged_node.left = TreeNode() + stack.append((node1.left, node2.left, merged_node.left)) + if not (node1.right is None and node2.right is None): + merged_node.right = TreeNode() + stack.append((node1.right, node2.right, merged_node.right)) + + return merged_root