diff --git a/617. Merge Two Binary Trees.md b/617. Merge Two Binary Trees.md new file mode 100644 index 0000000..c5e9b4d --- /dev/null +++ b/617. Merge Two Binary Trees.md @@ -0,0 +1,199 @@ +# step 1 + +再帰する解法。ノードの数が最大2000とあり、デフォルトのrecursion limit(1000)は超える。inner functionが多くなった。処理は簡単なので許容範囲と判断した。 + +root1, root2の深さの大きい方の数だけ再帰する。それぞれのノードの数をm, nとすると、 +- time complexity: O(m + n) +- space complexity: O(m + n) +```python +class Solution: + def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: + def get_val(node: Optional[TreeNode]) -> int: + if node is None: + return 0 + return node.val + def get_left(node: Optional[TreeNode]) -> Optional[TreeNode]: + if node is None: + return None + return node.left + def get_right(node: Optional[TreeNode]) -> Optional[TreeNode]: + if node is None: + return None + return node.right + + if root1 is None and root2 is None: + return None + + merged_val = get_val(root1) + get_val(root2) + merged_root = TreeNode(val=merged_val) + merged_root.left = self.mergeTrees(get_left(root1), get_left(root2)) + merged_root.right = self.mergeTrees( + get_right(root1), + get_right(root2) + ) + return merged_root +``` + +非再帰DFSを使う方法はバックトラックをどうすればいいかわからなかった。 + +# step 2 +- https://github.com/olsen-blue/Arai60/pull/23/files + - 片方がNoneになったとき、もう片方をそのままmergeしたtreeに繋げていた。 + - 非破壊だが、一部のオブジェクトを共有している + - コピーするなり、そのときNoneとなったノードをTreeNode(0)で上書きするなりしていた。 + - https://github.com/olsen-blue/Arai60/pull/23/files#r1929995500 +- https://github.com/tarinaihitori/leetcode/pull/23/files + - BFSによる解法。ノードとそれらをマージしたノードを持っていた。 + - https://github.com/tarinaihitori/leetcode/pull/23/files#r1919824481 + - 冗長さを排除した書き方。 + - pythonでもまだまだ知らない書き方があるなと感じた。 +- https://github.com/hroc135/leetcode/pull/22/files#r1826509019 + - stackに入りうるサイズの概算 + - > 事前に確保する配列の大きさをどの値にするのが有効かは実際に入力ノードの形状と大きさに依存するので、事前に最適なサイズを決定するのは難しいと思います +このサイズが性能にクリティカルな影響を与えるわけではないですが、ハードコードよりも環境変数などで外部から注入できるようにしたほうが良いと思いました + +DFS +- time complexity: O(m + n) +- space complexity: O(log(m + n)) +```python +class Solution: + def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: + def get_val(node: Optional[TreeNode]) -> int: + if node is None: + return 0 + return node.val + def get_left(node: Optional[TreeNode]) -> Optional[TreeNode]: + if node is None: + return None + return node.left + def get_right(node: Optional[TreeNode]) -> Optional[TreeNode]: + if node is None: + return None + return node.right + + if root1 is None and root2 is None: + return None + + merged_val = get_val(root1) + get_val(root2) + merged_root = TreeNode(val=merged_val) + stack = [(root1, root2, merged_root)] + while stack: + node1, node2, merged_node = stack.pop() + + node1_left = get_left(node1) + node2_left = get_left(node2) + if node1_left is not None or node2_left is not None: + left_val = get_val(node1_left) + get_val(node2_left) + merged_node.left = TreeNode(val=left_val) + stack.append((node1_left, node2_left, merged_node.left)) + + node1_right = get_right(node1) + node2_right = get_right(node2) + if node1_right is not None or node2_right is not None: + right_val = get_val(node1_right) + get_val(node2_right) + merged_node.right = TreeNode(val=right_val) + stack.append((node1_right, node2_right, merged_node.right)) + return merged_root +``` + +BFS +- time complexity: O(m + n) +- space complexity: O(log(m + n)) +```python +class Solution: + def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: + def get_val(node: Optional[TreeNode]) -> int: + if node is None: + return 0 + return node.val + def get_left(node: Optional[TreeNode]) -> Optional[TreeNode]: + if node is None: + return None + return node.left + def get_right(node: Optional[TreeNode]) -> Optional[TreeNode]: + if node is None: + return None + return node.right + + if root1 is None and root2 is None: + return None + + merged_val = get_val(root1) + get_val(root2) + merged_root = TreeNode(val=merged_val) + stack = [(root1, root2, merged_root)] + while stack: + node1, node2, merged_node = stack.pop() + + node1_left = get_left(node1) + node2_left = get_left(node2) + if node1_left is None and node2_left is None: + merged_node.left = None + else: + left_val = get_val(node1_left) + get_val(node2_left) + merged_node.left = TreeNode(val=left_val) + stack.append((node1_left, node2_left, merged_node.left)) + + node1_right = get_right(node1) + node2_right = get_right(node2) + if node1_right is None and node2_right is None: + merged_node.right = None + else: + right_val = get_val(node1_right) + get_val(node2_right) + merged_node.right = TreeNode(val=right_val) + stack.append((node1_right, node2_right, merged_node.right)) + return merged_root +``` + +もう少しコンパクトに書いたもの(https://github.com/tarinaihitori/leetcode/pull/23/files#r1919824481 の写経) +- time complexity: O(m + n) +- space complexity: O(log(m + n)) +```python +class Solution: + def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: + roots = list(filter(None, [root1, root2])) + if not roots: + return None + root = TreeNode() + stack = [(root, roots)] + while stack: + dst_node, src_nodes = stack.pop() + dst_node.val = sum(n.val for n in src_nodes) + + lefts = [n.left for n in src_nodes if n.left] + if lefts: + dst_node.left = TreeNode() + stack.append((dst_node.left, lefts)) + + rights = [n.right for n in src_nodes if n.right] + if rights: + dst_node.right = TreeNode() + stack.append((dst_node.right, rights)) + return root +``` + +# step 3 + +```python +class Solution: + def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: + def get_val(node: Optional[TreeNode]) -> int: + if node is None: + return 0 + return node.val + def get_left(node: Optional[TreeNode]) -> Optional[TreeNode]: + if node is None: + return None + return node.left + def get_right(node: Optional[TreeNode]) -> Optional[TreeNode]: + if node is None: + return None + return node.right + + if root1 is None and root2 is None: + return None + merged_val = get_val(root1) + get_val(root2) + merged_root = TreeNode(val=merged_val) + merged_root.left = self.mergeTrees(get_left(root1), get_left(root2)) + merged_root.right = self.mergeTrees(get_right(root1), get_right(root2)) + return merged_root +``` \ No newline at end of file