Leetcode Link: 617. 合并二叉树 - 力扣(LeetCode) (leetcode-cn.com)
题目
给你两棵二叉树: root1 和 root2 。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
返回合并后的二叉树。
注意: 合并过程必须从两个树的根节点开始。

解法一
思路:递归,深度优先搜索 问题中没提到不能修改树,因此就直接改变其中一个树就可以,避免新建了。
对于合并后的某个节点,有如下3类合并情况:
cur1和cur2都不为空,合并为相加- 其中一个为空,合并后是不为空的那个节点,同时递归结束(因为为空的那个节点后面没有子树了,因此合并后的对应节点下面都是不为空的节点的子树)
- 都为空,合并为
None,同时递归结束
直接在 root1 上进行修改,合并不仅在该节点,同时也在其子树的节点上。
题解: 我的版本(开始不会)
class Solution:
def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
if not root1 and not root2:
return None
if not root1:
return root2
if not root2:
return root1
# 合并
root1.val = root1.val + root2.val
# 直接在 root1 上修改
root1.left = self.mergeTrees(root1.left, root2.left)
root1.right = self.mergeTrees(root1.right, root2.right)
return root1 网友的简洁写法:
class Solution:
def mergeTrees(self, t1: TreeNode, t2: TreeNode) -> TreeNode:
if t1 and t2 :
t1.val += t2.val
t1.left = self.mergeTrees(t1.left, t2.left)
t1.right = self.mergeTrees(t1.right, t2.right)
return t1
return t1 or t2
# t1 t2都为空包含在内解法二
思路:宽度优先搜索 也可以使用广度优先搜索合并两个二叉树。首先判断两个二叉树是否为空,如果两个二叉树都为空,则合并后的二叉树也为空,如果只有一个二叉树为空,则合并后的二叉树为另一个非空的二叉树。
如果两个二叉树都不为空,则首先计算合并后的根节点的值,然后从合并后的二叉树与两个原始二叉树的根节点开始广度优先搜索,从根节点开始同时遍历每个二叉树,并将对应的节点进行合并。
使用三个队列分别存储合并后的二叉树的节点以及两个原始二叉树的节点。初始时将每个二叉树的根节点分别加入相应的队列。每次从每个队列中取出一个节点,判断两个原始二叉树的节点的左右子节点是否为空。如果两个原始二叉树的当前节点中至少有一个节点的左子节点不为空,则合并后的二叉树的对应节点的左子节点也不为空。对于右子节点同理。
如果合并后的二叉树的左子节点不为空,则需要根据两个原始二叉树的左子节点计算合并后的二叉树的左子节点以及整个左子树。考虑以下两种情况:
如果两个原始二叉树的左子节点都不为空,则合并后的二叉树的左子节点的值为两个原始二叉树的左子节点的值之和,在创建合并后的二叉树的左子节点之后,将每个二叉树中的左子节点都加入相应的队列;
如果两个原始二叉树的左子节点有一个为空,即有一个原始二叉树的左子树为空,则合并后的二叉树的左子树即为另一个原始二叉树的左子树,此时也不需要对非空左子树继续遍历,因此不需要将左子节点加入队列。
对于右子节点和右子树,处理方法与左子节点和左子树相同。
题解:
class Solution:
def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
if not root1 or not root2:
return root1 or root2
merge = TreeNode(val=root2.val+root1.val)
q1 = collections.deque()
q2 = collections.deque()
q3 = collections.deque()
q1.append(root1)
q2.append(root2)
q3.append(merge)
# q1和q2一定是相等的,因为只有遇到同位置节点有一个为空时还在入队才会导致不等
# 而实际上当其中一个为空的时候,后面就不需要入队了,直接把不空的接过来就可以
while(q1 and q2):
cur1 = q1.popleft()
cur2 = q2.popleft()
new = q3.popleft()
if cur1.right or cur2.right:
if cur1.right and cur2.right:
# 这里需要在入队前就考虑合并不合并,如果不需要合并,就干脆不入队,直接接过来
# 如果全都入队,出队后再合并,不仅分不清到底是左右节点,而且q1和q2会变得不相等
# 情况会变得更加复杂
new.right = TreeNode(val=cur1.right.val+cur2.right.val)
q1.append(cur1.right)
q2.append(cur2.right)
q3.append(new.right)
else:
# 仅有一个为空,那后面就不用看了,即就不用入队了
new.right = cur1.right or cur2.right
if cur1.left or cur2.left:
if cur1.left and cur2.left:
new.left = TreeNode(val=cur1.left.val+cur2.left.val)
q1.append(cur1.left)
q2.append(cur2.left)
q3.append(new.left)
else:
# 仅有一个为空,那后面就不用看了,即就不用入队了
new.left = cur1.left or cur2.left
return merge