文章目录
- 题目
- 标题和出处
- 难度
- 题目描述
- 要求
- 示例
- 数据范围
- 解法一
- 思路和算法
- 代码
- 复杂度分析
- 解法二
- 思路和算法
- 代码
- 复杂度分析
题目
标题和出处
标题:相同的树
出处:100. 相同的树
难度
3 级
题目描述
要求
给你两个二叉树的根结点 p \texttt{p} p 和 q \texttt{q} q,编写一个函数来检验这两个树是否相同。
如果两个树在结构上相同,并且结点具有相同的值,则认为它们是相同的。
示例
示例 1:
输入:
p
=
[1,2,3],
q
=
[1,2,3]
\texttt{p = [1,2,3], q = [1,2,3]}
p = [1,2,3], q = [1,2,3]
输出:
true
\texttt{true}
true
示例 2:
输入:
p
=
[1,2],
q
=
[1,null,2]
\texttt{p = [1,2], q = [1,null,2]}
p = [1,2], q = [1,null,2]
输出:
false
\texttt{false}
false
示例 3:
输入:
p
=
[1,2,1],
q
=
[1,1,2]
\texttt{p = [1,2,1], q = [1,1,2]}
p = [1,2,1], q = [1,1,2]
输出:
false
\texttt{false}
false
数据范围
- 两个树中的结点数目都在范围 [0, 100] \texttt{[0, 100]} [0, 100] 内
- -10 4 ≤ Node.val ≤ 10 4 \texttt{-10}^\texttt{4} \le \texttt{Node.val} \le \texttt{10}^\texttt{4} -104≤Node.val≤104
解法一
思路和算法
两个二叉树相同等价于两个二叉树的结构相同且相同位置的结点值相同。可以同时遍历两个二叉树,判断两个二叉树是否相同。
深度优先搜索的做法是,首先判断两个二叉树是否为空,如果两个二叉树都为空则两个二叉树相同,如果两个二叉树中只有一个为空则两个二叉树不同。
当两个二叉树都不为空时,可以递归判断两个二叉树是否相同。需要判断两个二叉树的根结点值是否相同、两个二叉树的左子树是否相同、两个二叉树的右子树是否相同,对左子树和右子树的判断使用递归的方式。只有当根结点、左子树和右子树都相同时,两个二叉树才相同。
代码
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) {
return true;
}
if (p == null || q == null) {
return false;
}
return p.val == q.val && isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}
复杂度分析
-
时间复杂度: O ( min ( m , n ) ) O(\min(m, n)) O(min(m,n)),其中 m m m 和 n n n 分别是两个二叉树的结点数。同时遍历两个二叉树,只有当两个二叉树在相同位置的结点都不为空时才会访问该位置的结点,因此访问的结点数不超过较小的二叉树的结点数。
-
空间复杂度: O ( min ( m , n ) ) O(\min(m, n)) O(min(m,n)),其中 m m m 和 n n n 分别是两个二叉树的结点数。空间复杂度主要是递归调用的栈空间,栈空间不超过较小的二叉树的高度,最坏情况下二叉树的高度和结点数相等。
解法二
思路和算法
也可以使用广度优先搜索遍历两个二叉树,判断两个二叉树是否相同。
使用两个队列分别存储两个二叉树的结点,同时遍历两个二叉树。初始时将两个二叉树的根结点分别入两个队列,遍历过程中,每次从两个队列分别将一个结点出队列,这两个出队列的结点一定是两个二叉树中的相同位置的结点,执行如下操作。
-
如果两个结点值不同,则两个二叉树的相同位置处的结点值不同,因此两个二叉树不同。
-
如果两个结点值相同,则分别获得两个结点的左子结点和右子结点,如果两个左子结点恰好有一个为空,或者两个右子结点恰好有一个为空,则两个二叉树的结构不同,因此两个二叉树不同。
-
如果两个结点的左子结点和右子结点的结构相同,则将的非空左子结点和右子结点分别入相应的队列。
当队列为空时,遍历结束,如果在任意位置,两个二叉树的结构都相同且结点值都相同,则两个二叉树相同。
代码
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) {
return true;
}
if (p == null || q == null) {
return false;
}
Queue<TreeNode> queue1 = new ArrayDeque<TreeNode>();
Queue<TreeNode> queue2 = new ArrayDeque<TreeNode>();
queue1.offer(p);
queue2.offer(q);
while (!queue1.isEmpty()) {
TreeNode node1 = queue1.poll();
TreeNode node2 = queue2.poll();
if (node1.val != node2.val) {
return false;
}
TreeNode left1 = node1.left, right1 = node1.right, left2 = node2.left, right2 = node2.right;
if (left1 == null ^ left2 == null) {
return false;
}
if (right1 == null ^ right2 == null) {
return false;
}
if (left1 != null) {
queue1.offer(left1);
queue2.offer(left2);
}
if (right1 != null) {
queue1.offer(right1);
queue2.offer(right2);
}
}
return true;
}
}
复杂度分析
-
时间复杂度: O ( min ( m , n ) ) O(\min(m, n)) O(min(m,n)),其中 m m m 和 n n n 分别是两个二叉树的结点数。同时遍历两个二叉树,只有当两个二叉树在相同位置的结点都不为空时才会访问该位置的结点,因此访问的结点数不超过较小的二叉树的结点数。
-
空间复杂度: O ( min ( m , n ) ) O(\min(m, n)) O(min(m,n)),其中 m m m 和 n n n 分别是两个二叉树的结点数。空间复杂度主要是队列空间,队列内元素个数不超过较小的二叉树的结点数。