相同的树 地址:https://leetcode.cn/problems/same-tree/
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
//思路
//其实也就是分为两部
//第一步就是先判断是否是空
//然后根节点和左树 和右数值是否一样
//这个遍历需要用前序加中序才可以确定一个结构
//这个题适合用递归
//先判断你这个根节点是不是空
if((p == null && q != null )||(p != null && q == null)) {
return false;
}
//走到这里有两种情况
//走到这里要不是就是比较就是被比较的最后了
if (p == null && q == null) {
return true;
}
if(p.val != q.val) {
return false;
}
return isSameTree(p.left,q.left) && isSameTree (p.right,q.right);
}
}“边遍历边对比” 的前提是 “同步遍历” —— 比如你的代码用的是 “同步前序遍历”,即:
这个过程中,树 A 的任何一个节点,都有且只有树 B 的一个 “对应节点” 与之匹配—— 比如树 A 根的左孩子,只对比树 B 根的左孩子;树 A 左孩子的右孩子,只对比树 B 左孩子的右孩子。 这种 “一一对应” 的遍历,确保了我们不会漏对比任何一个节点,也不会错配节点(比如用树 A 的左孩子对比树 B 的右孩子)。
我们以你的代码逻辑为例,把 “同步遍历” 拆成三个递进的判断步骤,每一步都在为 “结构一致” 和 “值一致” 做验证: **步骤 1:**先判断 “对应节点的存在性”(结构校验的核心) 遍历到任意一对对应节点(p 和 q)时,首先检查 “是否一个存在、一个不存在”:
if ((p == null && q != null) || (p != null && q == null)) {
return false; // 结构不一致:一个有节点,一个空
}if (p == null && q == null) {
return true; // 结构一致:该位置都空,无需再深入
}这是递归的 “终止条件”,也代表 “当前分支的结构完全一致”—— 因为两棵树在这个位置都没有更多节点了,不存在 “一方多节点、一方少节点” 的情况。 **步骤 3:**处理 “对应节点同时存在” 的情况(值校验 + 递归深入) 若当前对节点都非空(结构上暂时一致),则立刻校验它们的值:
if (p.val != q.val) {
return false; // 值不一致:结构虽对,但值错了
}这一步专门解决 “结构对但值错” 的场景(比如树 A 的节点值是 2,树 B 对应节点值是 3),值不同则直接返回false。 值校验通过后,必须递归深入到它们的左、右子树—— 因为 “当前节点对” 没问题,不代表 “它们的孩子节点对” 没问题:
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);这里的&&是关键:只有 “左子树的所有对应节点都一致”且“右子树的所有对应节点都一致”,当前节点对的校验才算通过。 递归会把 “左子树” 和 “右子树” 当成两棵新的小树,重复步骤 1-3—— 直到遍历完所有对应节点,或中途发现差异。 “前序 + 中序” 或 “后序 + 中序” 能唯一确定一棵二叉树的结构 那为什么不用“前序 + 中序” 或 “后序 + 中序” 能唯一确定一棵二叉树的结构,“前序 + 中序” 或 “后序 + 中序” 能唯一确定一棵二叉树的结构,这是二叉树结构还原的核心规则;但在 “判断两棵树是否相同” 的问题中,我们不需要 “还原结构”,而是 “直接对比结构”—— 两者的目标不同,因此方法也不同。 一、先明确:“前序 + 中序确定结构” 的适用场景 “前序 + 中序” 的核心作用是从 “遍历序列” 反向推导出 “二叉树的物理结构”,它解决的是 “已知序列,重建树” 的问题,而非 “已知两棵树,判断是否相同”。 举个例子:如果只给你 “前序序列 [1,2,3]”,你无法确定树的结构 —— 可能是 “根 1,左 2,右 3”,也可能是 “根 1,左 2,左 3”(链状)。但如果同时给你 “中序序列 [2,1,3]”,就能唯一确定结构是 “根 1,左 2,右 3”。 这里的关键是:当你只有 “单个遍历序列” 时,无法确定结构;必须结合两种序列,才能反向还原出唯一的树结构。 二、“判断两棵树是否相同” 为何不需要 “先求序列再对比”? 因为我们已经有了 “两棵树的完整物理结构”(函数参数 p 和 q 就是两棵树的根节点,能直接访问每个节点的左 / 右孩子),不需要 “通过序列间接推导结构”—— 我们可以直接同步遍历两棵树,逐节点对比 “结构一致性”,这比 “先求序列再对比” 更高效(少了 “生成序列” 的步骤)。 具体来说,你的代码本质上是 “同步前序遍历” 两棵树,在遍历过程中同时完成两件事:
这种 “边遍历边对比” 的方式,一旦发现差异(结构或值不同),能立刻返回 false,无需遍历完整棵树 —— 而 “先求序列再对比” 需要遍历完两棵树、生成序列后才能对比,效率更低。 三、如果用 “前序 + 中序” 判断,会怎么做?(对比理解) 虽然没必要,但我们可以通过 “生成序列再对比” 的思路,理解两种方法的差异,从而更清楚你的代码为何更优。步骤如下:
示例:用该方法验证 “示例 2(结构不同)” p = [1,2] 的前序序列:[1,2],中序序列:[2,1]; q = [1,null,2] 的前序序列:[1,null,2],中序序列:[1,2]; 对比发现:前序序列不同([1,2] vs [1,null,2]),中序序列也不同([2,1] vs [1,2])→ 判定不同。 但这种方法的问题: