一、题目描述
给你两棵二叉树的根节点 p
和 q
,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入:p = [1,2,3], q = [1,2,3] 输出:true
示例 2:
输入:p = [1,2], q = [1,null,2] 输出:false
示例 3:
输入:p = [1,2,1], q = [1,1,2] 输出:false
提示:
- 两棵树上的节点数目都在范围
[0, 100]
内 -10^4 <= Node.val <= 10^4
二、解题思路
- 递归比较两棵树的节点。
- 首先判断当前节点是否都为空,都为空则返回true。
- 然后判断当前节点是否只有一个为空,或者当前节点的值不相等,这两种情况都返回false。
- 接着递归比较左子树和右子树。
三、具体代码
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) {
return true;
}
if (p == null || q == null || p.val != q.val) {
return false;
}
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}
四、时间复杂度和空间复杂度
1. 时间复杂度
- 我们需要访问每棵树中的每个节点一次,以确定它们是否相同。
- 假设两棵树都有
n
个节点,那么时间复杂度是O(n)
,因为每个节点只被访问一次。
2. 空间复杂度
- 递归调用会使用栈空间,其空间复杂度取决于树的高度。
- 在最坏的情况下,树完全不平衡,例如每个节点都只有左子节点或者只有右子节点,递归的深度会是
O(n)
,因此空间复杂度也是O(n)
。 - 在最好的情况下,树是完全平衡的,递归的深度是
O(log n)
,因此空间复杂度是O(log n)
。
综上所述,时间复杂度是 O(n)
,空间复杂度在最坏情况下是 O(n)
,在最好情况下是 O(log n)
。
五、总结知识点
-
递归:这是一种常用的算法技巧,用于解决可以分解为更小子问题的问题。在这个问题中,我们检查两棵树是否相同,可以通过递归地检查它们的子树是否相同来实现。
-
二叉树遍历:代码中隐式地使用了深度优先搜索(DFS)来遍历二叉树的节点。这是一种常用的二叉树遍历算法,它通过递归先访问根节点,然后遍历左子树,最后遍历右子树。
-
引用比较:在Java中,
==
操作符用于比较引用类型时,会比较两个引用是否指向堆内存中的同一个对象。在这个问题中,我们使用==
来检查两个节点是否都为null
。 -
逻辑运算符:代码中使用了逻辑与运算符
&&
来组合两个布尔表达式的结果。这要求两个表达式都为true
时,整个表达式的结果才为true
。 -
条件语句:代码中使用了
if-else
语句来根据节点的状态做出决策。这是编程中基本的控制流结构,用于根据条件执行不同的代码路径。 -
函数定义:代码定义了一个名为
isSameTree
的函数,它接受两个TreeNode
类型的参数,并返回一个布尔值。这是面向对象编程中封装和抽象的基本概念。 -
递归终止条件:在递归函数中,必须有一个或多个终止条件以避免无限递归。在这个问题中,递归的终止条件是当两个节点都为
null
时返回true
,或者当一个节点为null
而另一个不是时返回false
。 -
节点结构:代码中使用了
TreeNode
类来表示二叉树的节点,每个节点包含一个整数值val
和两个指向其子节点的引用left
和right
。这是二叉树在计算机科学中的基本表示方式。
以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。