当前位置: 首页 > news >正文

力扣刷题——二叉树相同的树

相同的树
地址: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);}
}

“边遍历边对比” 的前提是 “同步遍历” —— 比如你的代码用的是 “同步前序遍历”,即:

  1. 先对比两棵树的根节点;
  2. 再同步递归对比两棵树的左子树(根的左孩子及其后代);
  3. 最后同步递归对比两棵树的右子树(根的右孩子及其后代)。

这个过程中,树 A 的任何一个节点,都有且只有树 B 的一个 “对应节点” 与之匹配—— 比如树 A 根的左孩子,只对比树 B 根的左孩子;树 A 左孩子的右孩子,只对比树 B 左孩子的右孩子。
这种 “一一对应” 的遍历,确保了我们不会漏对比任何一个节点,也不会错配节点(比如用树 A 的左孩子对比树 B 的右孩子)。

在遍历中 “同时验证结构和值”

我们以你的代码逻辑为例,把 “同步遍历” 拆成三个递进的判断步骤,每一步都在为 “结构一致” 和 “值一致” 做验证:
**步骤 1:**先判断 “对应节点的存在性”(结构校验的核心)
遍历到任意一对对应节点(p 和 q)时,首先检查 “是否一个存在、一个不存在”:

if ((p == null && q != null) || (p != null && q == null)) {return false; // 结构不一致:一个有节点,一个空
}
  • 这一步直接卡住 “结构差异” 的核心场景:比如树 A 在某个位置有节点,树 B 在同一个位置空着 —— 这种
    “对应位置存在性不同”,就是结构不同的直接证据,立刻返回false。
  • 反之,若通过这一步,说明当前对节点 “同时存在” 或 “同时不存在”—— 结构上暂时无问题,进入下一步。
    **步骤 2:**处理 “对应节点同时不存在” 的情况(结构校验的终止)
    若当前对节点都是null(比如两棵树的左子树都遍历到了叶子节点的下一层):
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 就是两棵树的根节点,能直接访问每个节点的左 / 右孩子),不需要 “通过序列间接推导结构”—— 我们可以直接同步遍历两棵树,逐节点对比 “结构一致性”,这比 “先求序列再对比” 更高效(少了 “生成序列” 的步骤)。
具体来说,你的代码本质上是 “同步前序遍历” 两棵树,在遍历过程中同时完成两件事:

  1. 结构校验:判断当前对应节点是否 “同时为空” 或 “同时非空”(避免 “一个有节点、一个空” 的结构差异);
  2. 值校验:若节点非空,判断值是否相等。

这种 “边遍历边对比” 的方式,一旦发现差异(结构或值不同),能立刻返回 false,无需遍历完整棵树 —— 而 “先求序列再对比” 需要遍历完两棵树、生成序列后才能对比,效率更低。
三、如果用 “前序 + 中序” 判断,会怎么做?(对比理解)
虽然没必要,但我们可以通过 “生成序列再对比” 的思路,理解两种方法的差异,从而更清楚你的代码为何更优。步骤如下:

  • 分别对 p 和 q 求 “前序遍历序列” 和 “中序遍历序列”;
  • 对比 p 和 q 的 “前序序列” 是否完全一致,且 “中序序列” 是否完全一致;
  • 若两个序列都一致,则两棵树结构和值均相同;否则不同。

示例:用该方法验证 “示例 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])→ 判定不同。
但这种方法的问题:

  • 效率低:需要遍历两棵树至少 2 次(前序 + 中序),还需要额外空间存储序列;
  • 冗余:已知树的物理结构,却要先转成序列再对比,多此一举。
http://www.dtcms.com/a/458677.html

相关文章:

  • 上海奉贤网站建设免费二维码制作生成器
  • 株洲企业网站建设工作网站建设一般预付比例多少
  • 嵌入式 Linux(以泰山派为例)忘记 SSH 密码怎么办?无需重装系统的重置方案
  • 餐饮行业做网站的数据广州网站建设广州网络推广公司排名
  • 织梦网络公司网站源码招投标 网站建设
  • 爱做网站网址wordpress建淘宝客
  • 汉中市网站建设公司淘宝买模板注浆做网站
  • 做网站的linux程序代码爱深圳小程序
  • Unity网络开发--套接字Socket(1)
  • 南京做网站的有哪些学生个人网页制作主题
  • 【LLM】ms-Swift大模型训练框架源码分析
  • 安全电子商务网站设计一个网站怎么绑定很多个域名
  • Docker镜像
  • 网站部署环境推广平台怎么赚钱
  • 2817网站中山网站建设制作
  • 【Algorithm】Day-2
  • 淘宝网站那个做的最好加盟网站建设
  • 本地的丹阳网站建设合肥大型网站
  • 做网站登录平台网站是什么
  • 个人用云计算学习笔记 --21(Linux 文本处理工具与正则表达式)
  • 室内装饰公司网站模板wordpress 主题上传
  • 网站迁移到别的服务器要怎么做人力资源公司简介
  • 第六步:加入日志功能
  • 16.C++三大重要特性之多态
  • 鄂州网站建设网站建设的界面f分
  • 网站添加对联广告代码shine跨境电商平台
  • Linux VScode 安装PHP环境
  • 云速建站与传统网站的区别在线设计装修软件
  • 南安建设局网站wordpress英文模版
  • leaflow 部署openlist 部署教程