来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/same-tree
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
输入:p = [1,2,3], q = [1,2,3]
输出:true
输入:p = [1,2], q = [1,null,2]
输出:false
输入:p = [1,2,1], q = [1,1,2]
输出:false
感觉用递归呀
(1)深度优先搜索
链接:https://leetcode-cn.com/problems/same-tree/solution/xiang-tong-de-shu-by-leetcode-solution/
如果两个二叉树都为空,则两个二叉树相同。如果两个二叉树中有且只有一个为空,则两个二叉树一定不相同。
如果两个二叉树都不为空,那么首先判断它们的根节点的值是否相同,若不相同则两个二叉树一定不同,若相同,再分别判断两个二叉树的左子树是否相同以及右子树是否相同。
这是一个递归的过程,因此可以使用深度优先搜索,递归地判断两个二叉树是否相同。
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
if not p and not q: # 都为空,则相同
return True
elif not p or not q: # 有一个为空,则两个树不同
return False
elif p.val != q.val: # 根节点值不同,返回False
return False
else:
# 递归判断左节点和右节点
return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
复杂度分析
时间复杂度:O(min(m,n)),其中 m和 n分别是两个二叉树的节点数。对两个二叉树同时进行深度优先搜索,只有当两个二叉树中的对应节点都不为空时才会访问到该节点,因此被访问到的节点数不会超过较小的二叉树的节点数。
空间复杂度:O(min(m,n)),其中 m 和 n 分别是两个二叉树的节点数。空间复杂度取决于递归调用的层数,递归调用的层数不会超过较小的二叉树的最大高度,最坏情况下,二叉树的高度等于节点数
(2)广度优先搜索
链接:https://leetcode-cn.com/problems/same-tree/solution/xiang-tong-de-shu-by-leetcode-solution/
同样首先判断两个二叉树是否为空,如果两个二叉树都不为空,则从两个二叉树的根节点开始广度优先搜索。
使用两个队列分别存储两个二叉树的节点。初始时将两个二叉树的根节点分别加入两个队列。每次从两个队列各取出一个节点,进行如下比较操作。
1.比较两个节点的值,如果两个节点的值不相同则两个二叉树一定不同;
2.如果两个节点的值相同,则判断两个节点的子节点是否为空,如果只有一个节点的左子节点为空,或者只有一个节点的右子节点为空,则两个二叉树的结构不同,因此两个二叉树一定不同;
3.如果两个节点的子节点的结构相同,则将两个节点的非空子节点分别加入两个队列,子节点加入队列时需要注意顺序,如果左右子节点都不为空,则先加入左子节点,后加入右子节点。
如果搜索结束时两个队列同时为空,则两个二叉树相同。如果只有一个队列为空,则两个二叉树的结构不同,因此两个二叉树不同。
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
if not p and not q:
return True
if not p or not q:
return False
queue1 = collections.deque([p])
queue2 = collections.deque([q])
while queue1 and queue2:
node1 = queue1.popleft() # 队头节点出 效果等同queue.pop(0)
node2 = queue2.popleft()
if node1.val != node2.val: # 比较两个节点的值,不同返回False
return False
left1, right1 = node1.left, node1.right # 此时的node应该是树中的根节点,并不是按照队列来看的,所以有left
print('left1, right1:', left1, right1)
left2, right2 = node2.left, node2.right
if (not left1) ^ (not left2):
# ^异或运算:1对1为0;1对0是1;0对1是1;0对0是0, 相同为0 不同为1
# False 0 True 1 True的时候执行if 也就是两个不同时候返回False
return False
if (not right1) ^ (not right2):
return False
if left1:
queue1.append(left1)
if right1:
queue1.append(right1)
if left2:
queue2.append(left2)
if right2:
queue2.append(right2)
return not queue1 and not queue2
复杂度分析
时间复杂度:O(min(m,n)),其中 m 和 n 分别是两个二叉树的节点数。对两个二叉树同时进行广度优先搜索,只有当两个二叉树中的对应节点都不为空时才会访问到该节点,因此被访问到的节点数不会超过较小的二叉树的节点数。
空间复杂度:O(min(m,n)),其中 m 和 n 分别是两个二叉树的节点数。空间复杂度取决于队列中的元素个数,队列中的元素个数不会超过较小的二叉树的节点数。