Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions arai60/21-29_Tree_BT_BST/23_617_Merge Two Binary Trees/level_1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# DFS(破壊的)
class Solution:
def mergeTrees(
self, root1: Optional[TreeNode], root2: Optional[TreeNode]
) -> Optional[TreeNode]:
if not root1 and not root2:
return None
if not root2:
return root1
if not root1:
return root2
root1.val += root2.val
root1.left = self.mergeTrees(root1.left, root2.left)
root1.right = self.mergeTrees(root1.right, root2.right)
return root1


# BFS(破壊的)
class Solution:
def mergeTrees(
self, root1: Optional[TreeNode], root2: Optional[TreeNode]
) -> Optional[TreeNode]:

if not root1:
return root2
if not root2:
return root1
nodes_queue = deque([(root1, root2)])
root1.val += root2.val
while nodes_queue:
node1, node2 = nodes_queue.popleft()
if node1.left and node2.left:
node1.left.val += node2.left.val
nodes_queue.append((node1.left, node2.left))
if not node1.left:
node1.left = node2.left
if node1.right and node2.right:
node1.right.val += node2.right.val
nodes_queue.append((node1.right, node2.right))
if not node1.right:
node1.right = node2.right
return root1
46 changes: 46 additions & 0 deletions arai60/21-29_Tree_BT_BST/23_617_Merge Two Binary Trees/level_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# DFS
# 非破壊的に修正
class Solution:
def mergeTrees(
self, root1: Optional[TreeNode], root2: Optional[TreeNode]
) -> Optional[TreeNode]:
def helper_merge_trees(node1, node2):
if not node1 and not node2:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

このif文はなくても動くと思います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

不要なif文でしたので削除します。
解法が整理しきれてませんでしたね。

return None
if not node2:
return node1
if not node1:
return node2
node1.val += node2.val
node1.left = helper_merge_trees(node1.left, node2.left)
node1.right = helper_merge_trees(node1.right, node2.right)
return node1

sum_tree = deepcopy(root1)
return helper_merge_trees(sum_tree, root2)


# BFS
# 非破壊的に修正
# nodeの結合を関数化
class Solution:
def mergeTrees(
self, root1: Optional[TreeNode], root2: Optional[TreeNode]
) -> Optional[TreeNode]:

def merge_nodes(node1, node2, queue):
if node1 and node2:
node1.val += node2.val
queue.append((node1, node2))
if not node1:
node1 = node2
return node1, queue

nodes_queue = deque()
sum_tree = deepcopy(root1)
sum_tree, nodes_queue = merge_nodes(sum_tree, root2, nodes_queue)
while nodes_queue:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

なんかものすごく読みづらいんですよね。queueを引数で取り回しているからですかね?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

確かに変な書き方になっている気がします。
helper_merge_treesを呼ぶと気づいたらnodes_queueに追加されていて利用者がびっくりすることを避けたかったんですよね。
イマイチなのは分かるんですが、直し方がわからないですね...

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

メインのwhileループで1番気になるのが、queueのライフサイクル(いつ取り出されていつ何が入ってくるのか)だと思うんですけど、関数の中でやってしまうとそこが追いづらいのがあるのかなと思います。

うーん、書いてみたんですけどあんまり良くなっていないかもです。二分木で親と子の繋ぎ変えが発生する場合はBFSだと書きにくいですね。

class Solution:
    def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
        def merge_nodes(node1, node2):
            if not node1:
                return copy.deepcopy(node2)
            if not node2:
                return node1
            node1.val += node2.val
            return node1

        root1_clone = copy.deepcopy(root1)
        merged_tree_root = merge_nodes(root1_clone, root2)
        queue = deque()
        if root1_clone and root2:
            queue.append((root1_clone, root2))
        while queue:
            node1, node2 = queue.popleft()
            # 本当はqueueへの追加と左右のマージの処理の順番は逆にしたいがnode1.left, node1.rightを書き換えるのでこの順番でないといけない。
            if node1.left and node2.left:
                queue.append((node1.left, node2.left))
            if node1.right and node2.right:
                queue.append((node1.right, node2.right))
            node1.left = merge_nodes(node1.left, node2.left)
            node1.right = merge_nodes(node1.right, node2.right)
        return merged_tree_root

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。
関数外でqueueの追加をするこちらの方がベターだと思いました。

node1, node2 = nodes_queue.popleft()
node1.left, nodes_queue = merge_nodes(node1.left, node2.left, nodes_queue)
node1.right, nodes_queue = merge_nodes(node1.right, node2.right, nodes_queue)
return sum_tree
18 changes: 18 additions & 0 deletions arai60/21-29_Tree_BT_BST/23_617_Merge Two Binary Trees/level_3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class Solution:
def mergeTrees(
self, root1: Optional[TreeNode], root2: Optional[TreeNode]
) -> Optional[TreeNode]:
def helper_merge_tree(node1, node2):
if not node1 and not node2:
return None
if not node1:
return node2
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

root2をルートとするツリーについては、引数で渡ってきたものをそのまま使用しているので、この書き方だとmergeTreesの返り値のTreeにroot2の一部が使われてしまいます。この関数自体では非破壊的かもしれないですが、mergeTreesの返り値のTreeの操作を行うとroot2のツリーを書き換えてしまう可能性があります。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

返り値のTreeが中途半端でたちが悪くなっていることに気づきませんでした。
戻り値にdeepcopyが必要ですね。

if not node2:
return node1
node1.val += node2.val
node1.left = helper_merge_tree(node1.left, node2.left)
node1.right = helper_merge_tree(node1.right, node2.right)
return node1

sum_tree = deepcopy(root1)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

sum_treeの命名がなんか気になります。merged_treeのほうが良いかなと思います。あと実際には、これはマージしたツリーではなく単にroot1のコピーなのでroot1_cloneとかですかね。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

コピーした時点ではmerged_treeではないので命名が良くないことは、とても参考になりました。

return helper_merge_tree(sum_tree, root2)
44 changes: 44 additions & 0 deletions arai60/21-29_Tree_BT_BST/23_617_Merge Two Binary Trees/level_4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# DFS(非破壊)
# レビューコメントを反映
# helper関数をなくした
class Solution:
def mergeTrees(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ヘルパー関数なしでも書けそうですね。

self, root1: Optional[TreeNode], root2: Optional[TreeNode]
) -> Optional[TreeNode]:
if not root2:
return deepcopy(root1)
if not root1:
return deepcopy(root2)
node = TreeNode(root1.val + root2.val)
node.left = self.mergeTrees(root1.left, root2.left)
node.right = self.mergeTrees(root1.right, root2.right)
return node

# BFS(非破壊)
# レビューコメントを反映
class Solution:
def mergeTrees(
self, root1: Optional[TreeNode], root2: Optional[TreeNode]
) -> Optional[TreeNode]:

def merge_nodes(node1, node2):
if not node2:
return deepcopy(node1)
if not node1:
return deepcopy(node2)
new_node = TreeNode(node1.val + node2.val)
return new_node

merged_root = merge_nodes(root1, root2)
nodes_queue = deque()
if root1 and root2:
nodes_queue.append((merged_root, root1, root2))
while nodes_queue:
merged_node, node1, node2 = nodes_queue.popleft()
merged_node.left = merge_nodes(node1.left, node2.left)
merged_node.right = merge_nodes(node1.right, node2.right)
if node1.left and node2.left:
nodes_queue.append((merged_node.left, node1.left, node2.left))
if node1.right and node2.right:
nodes_queue.append((merged_node.right, node1.right, node2.right))
return merged_root