100. 相同的树
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入: p = [1,2,3], q = [1,2,3]
输出: true
问题分析
要判断两棵二叉树是否相同,需要同时满足:
- 结构相同:两棵树的形状完全一致
- 点值相同:对应位置的节点值相等
解题思路
方法一:递归(深度优先搜索)
核心思想:
- 如果两个节点都为空,返回 true
- 果其中一个为空,另一个不为空,返回 false
- 果两个节点都不为空但值不相等,返回 false
- 如果两个节点值相等,则递归比较左子树和右子树
递归终止条件:
- 两个节点都为 null → 相同
- 个为 null,另一个不为 null → 不同
- 个节点值不相等 → 不同
递归关系:
当前节点相同 = 节点值相等 && 左子树相同 && 右子树相同
代码实现
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
// 递归终止条件1:两个节点都为空,相同
if (p == null && q == null) {
return true;
}
// 递归终止条件2:其中一个为空,另一个不为空,不同
if (p == null || q == null) {
return false;
}
// 递归终止条件3:两个节点值不相等,不同
if (p.val != q.val) {
return false;
}
// 递归比较左子树和右子树
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}
方法二:迭代(层次遍历)
核心思想:
- 使用队列同时遍历两棵树
- 每次从队列中取出两个对应的节点进行比较
- 将对应的子节点按相同顺序加入队列
步骤:
- 将两个根节点入队
- 当队列不为空时,取出两个节点比较
- 如果节点值不同或结构不同,返回 false
- 将对应的左右子节点入队继续比较
代码实现
public boolean isSameTree(TreeNode p, TreeNode q) {
// 边界情况:两个都为空
if (p == null && q == null) {
return true;
}
// 边界情况:其中一个为空
if (p == null || q == null) {
return false;
}
// 使用队列进行层次遍历
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(p);
queue.offer(q);
while (!queue.isEmpty()) {
// 每次取出两个对应的节点
TreeNode node1 = queue.poll();
TreeNode node2 = queue.poll();
// 如果两个节点都为空,继续下一轮
if (node1 == null && node2 == null) {
continue;
}
// 如果其中一个为空或值不相等,返回false
if (node1 == null || node2 == null || node1.val != node2.val) {
return false;
}
// 将对应的子节点按顺序加入队列
queue.offer(node1.left);
queue.offer(node2.left);
queue.offer(node1.right);
queue.offer(node2.right);
}
return true;
}
时间复杂度和空间复杂度
-
时间复杂度:
- O(min(m,n))O(min(m,n))O(min(m,n)),其中 mmm 和 nnn 分别是两棵树的节点数
-
空间复杂度:
- 递归:O(min(m,n))O(min(m,n))O(min(m,n)),递归调用栈的深度
- 迭代:O(min(m,n))O(min(m,n))O(min(m,n)),队列存储的节点数