发布时间:2026/9/7 4:13:52
CS-Notes 剑指 Offer 第 26 题详解:用两段递归类函数实现二叉树子结构匹配 CS-Notes 剑指 Offer 第 26 题详解用两段递归类函数实现二叉树子结构匹配【免费下载链接】CS-Notes:books: 技术面试必备基础知识、Leetcode、计算机操作系统、计算机网络、系统设计项目地址: https://gitcode.com/GitHub_Trending/cs/CS-Notes本文基于 CS-Notes 仓库中 剑指 Offer 题解 - 树的子结构 一文展开完整继承其题目描述与官方解法代码并结合该仓库其他树类题解如 二叉树的镜像、对称的二叉树中的同构递归套路深入剖析“子结构判定”的两段式递归设计、空树边界的语义约定以及复杂度与易错点帮助读者掌握二叉树模式匹配类面试题的标准解法与变形思路。题目描述剑指 Offer 第 26 题“树的子结构”的原始定义如下输入两棵二叉树 A 和 B判断 B 是不是 A 的子结构。约定空树不是任意树的子结构即空树不算作 A 的子结构。直观示例如下图所示树root2右图是否是树root1左图的子结构。在《剑指 Offer》的解题约定中“B 是 A 的子结构”需要满足一个结构性条件存在 A 中的某个节点 N使得以 N 为根的子树与 B 的结构一致对应节点值相等且 B 中不存在的子节点不影响判定——也就是说匹配只要求 B 中已有的节点在 A 的对应位置上找到值相等的节点B 中为空的分支不要求 A 中也为空。这一约定是理解后续代码中所有终止条件的关键。核心思路全局搜索 局部验证的两段式递归子结构判定天然可以拆解为两个相互递归的子问题这也是该题解法代码中两个函数的分工全局搜索HasSubtree以root1的每一个节点为候选起点尝试让root2从该节点开始匹配。若当前节点匹配成功则返回 true否则依次退回其左子树、右子树继续搜索局部验证isSubtreeWithRoot假设两棵树的当前根节点已经对齐逐层向下验证“以root2当前节点为根的结构是否完全被root1对应位置覆盖”。两者形成经典的“外层遍历候选根、内层验证匹配”模式与 对称的二叉树 中“双指针同步下探两棵树”、二叉树的镜像 中“前序递归交换”属于同一族“对两棵或同一棵的树做同步递归”的套路。完整解法代码与逐行解析以下代码完整来自仓库原文档 26. 树的子结构是牛客网在线判题环境下的标准 Java 实现public boolean HasSubtree(TreeNode root1, TreeNode root2) { if (root1 null || root2 null) return false; return isSubtreeWithRoot(root1, root2) || HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2); } private boolean isSubtreeWithRoot(TreeNode root1, TreeNode root2) { if (root2 null) return true; if (root1 null) return false; if (root1.val ! root2.val) return false; return isSubtreeWithRoot(root1.left, root2.left) isSubtreeWithRoot(root1.right, root2.right); }逐行说明入口防御root1 null || root2 null时直接返回 false。root1为空说明没有候选起点自然不存在子结构root2为空时此实现也返回 false等价于采用了“空树不是任意树子结构”的判题口径见下一节对两种约定的讨论。短路求值的候选遍历isSubtreeWithRoot(root1, root2) || HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2)一行完成了“先验证当前根、再向左右子树扩散”的全局搜索。||的短路特性保证一旦某个起点验证成功后续子树不再被访问平均情况下可以提前退出。内层验证的三种终止root2 null返回 true表示root2的结构已经全部匹配完毕剩下root1侧多出的节点不影响结论——这正是“子结构”区别于“两棵树完全相同”的语义所在root1 null返回 falseroot2还有剩余结构但root1侧已经没有节点可对应验证失败节点值不等返回 false结构对齐的前提是值相等一旦不等立即剪枝递归下探值相等时同时递归左右两侧任何一侧失败即整体失败与 对称的二叉树 中isSymmetrical(t1.left, t2.right) isSymmetrical(t1.right, t2.left)的同步下探写法结构一致。空树语义约定为什么两处空判断“一真一假”读这段代码时最容易产生疑问的是同为遇到空节点HasSubtree里root2 null返回 false而isSubtreeWithRoot里root2 null却返回 true。这两处并不矛盾而是分别服务于不同的判定时机入口处HasSubtree第一行root2作为整体输入就是空树。按《剑指 Offer》的题目约定空树不被认为是任何树的子结构因此直接拒绝避免把“空对非空”误判为成功验证过程中isSubtreeWithRoot第一行root2是在递归下探途中“用完了”即它的剩余部分已经与root1的某个子树逐节点匹配完毕返回 true 是“匹配完成”的正常收尾而不是“空树等于任意树”。这种组合使代码同时兼容两种常见判题口径若采用《剑指 Offer》2019 版/LeetCode 572 风格空树不算子结构入口的root2 null分支已经兜底若采用“空树是任意树子结构”的宽松定义只需将入口处的root2 null改为返回 true 即可内层验证逻辑保持不变。理解这一点对后续应对面试官追问“空树怎么处理”至关重要。复杂度分析设root1的节点数为 Mroot2的节点数为 N时间复杂度最坏情况下root1的每个节点都会触发一次对root2的完整结构验证例如所有节点值都相同、直到深处才出现结构差异总代价为 O(M×N)由于短路求值平均情况下实际访问的节点对远小于 M×N空间复杂度仅来自递归调用栈外层搜索深度最深 M 层内层验证深度最深 N 层合计 O(M N)。对于面试中更常见的中等规模输入该递归解法已经足够题目本身也未要求优化到线性级别重点在于把递归边界讲清楚。边界与易错点清单root2只有一侧子树如root2根节点只有左孩子验证root1对应节点时其右孩子可以为空也可以非空内层递归对root2.right null直接返回 true这是“子结构”而非“相等子树”的直接体现值相等但结构不同isSubtreeWithRoot会因在第一个结构不匹配的分支立刻返回 false不会继续浪费搜索单节点树root1、root2都只有一个节点且值相等时两侧递归均在root2 null处返回 true结果为 true值不等则入口比较即失败常见写法错误把内层验证的root2 null误写为 false、或忘记入口对root1 null的防御虽然isSubtreeWithRoot能处理root1为空但入口提前剪枝可避免一次无意义的调用。与同类题的关系及延伸若把判定条件从“子结构”收紧为“完全相同的子树”则只需将isSubtreeWithRoot中root2 null的返回值由 true 改为root1 null其余搜索框架不变即得到 LeetCode 572“另一棵树的子树”的判定方式该题不认为空树是子树入口对root2 null返回 false 与其口径一致若 B 是有序序列而 A 是二叉树则演变为“验证前序/后序序列是否对应树结构”一类问题可参考仓库中 7. 重建二叉树 对“遍历序列与树结构互推”的分析递归同步下探两棵树的模板还出现在 28. 对称的二叉树对称即“左子树与右子树互为镜像”中掌握本节两段式结构后这类题基本是同构替换更多二叉树面试题层序打印、路径和等可在 剑指 Offer 题解 - 目录 的“树”分类下按题号继续学习。小结树的子结构一题的精髓在于把“匹配”与“搜索”拆成两个递归函数外层HasSubtree负责在root1上枚举所有候选根并借助短路求值提前退出内层isSubtreeWithRoot负责在根对齐的前提下逐节点验证并用root2 null → true表达“结构已匹配完整”的语义。理解入口空树防御与验证过程空树收尾这两处空判断的分工是该题答到面试官点头的关键再结合 O(M×N) 最坏时间的复杂度说明即可完成一次完整而严谨的作答。【免费下载链接】CS-Notes:books: 技术面试必备基础知识、Leetcode、计算机操作系统、计算机网络、系统设计项目地址: https://gitcode.com/GitHub_Trending/cs/CS-Notes创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

2026/9/7 4:13:52

从零手写BP神经网络:Python实现手写数字识别

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/7 11:09:27

CMSIS-DSP深度评测:从源码审计到工业落地,FFT性能提升20倍

上个月帮朋友排查一个电力监测设备的谐波异常,最后定位到问题不是算法逻辑,而是性能:他自己写的FFT在Cortex-M4F上跑一次1024点变换要超过3ms,ADC采样窗口还在持续往缓冲区里灌数据,导致每次算完的频谱窗口几乎错位了半…

2026/9/7 11:09:27

单例模式深度剖析:各种实现方式的优缺点对比

目录 一、单例模式的定义和应用场景 (一)定义及基本要点 (二)应用场景 二、饿汉式单例模式 (一)基本代码展示分析 (二)基本分析和建议 三、懒汉式单例模式(双重检…

2026/9/7 11:09:27

直击高频编程考点:动态规划经典算法题总结

目录 一、动态规划总结 (一)基本理解 (二)应用分析 二、相关高频笔试题目练习 (一)最大子序和(Maximum Subarray) (二)最长上升子序列(Longest Increasing Subsequence) (三)最长公共子序列(Longest Common Subsequence) (四)最大子数组乘积(Maximu…

2026/9/7 11:09:27

AI视频创作全流程实战:从提示词到短剧成片

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/7 0:47:43

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/7 0:14:19

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/7 0:14:17

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/7 0:03:36

基于YOLOv8和PyQt5的麦穗稻穗检测识别系统设计与实现

这次我们来看一个把目标检测算法和桌面端工具结合得很典型的项目:基于 YOLOv8 PyQt5 的麦穗稻穗检测识别系统。这个项目本身不是新概念,但它的价值在于落地形态很完整。YOLOv8 负责核心的麦穗稻穗目标检测,PyQt5 负责提供可视化的桌面交互界…

2026/9/7 0:03:36

UL 1642锂电池安全标准全解析:测试项目、认证流程与避坑指南

简介:UL 1642是锂电池安全领域的重要规范,本中文版资源适合锂电池制造商、检测机构工程师及产品认证相关人员阅读,用于理解电池在设计与制造层面的安全要求、测试方法与合规要点。资源共1个PDF文件,压缩包大小834KB,便…

2026/9/7 0:03:36

BS EN 13814-1-2019游乐设施安全标准:设计与制造核心要点解析

简介:BS EN 13814-1:2019是英国采纳欧洲标准EN 13814-1:2019的正式版本,由BSI标准出版,重点规定游乐设施和游乐设备在设计与制造环节的安全准则,与BS EN 13814-2:2019、BS EN 13814-3:2019共同取代旧版BS EN 13814:2004。该标准面…

2026/9/6 11:40:10

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/6 19:33:50

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/6 10:19:40

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…