剑指 Offer 28. 对称的二叉树:三种解法详解与递归/迭代思路剖析
文档教程知识库【免费下载链接】InterviewGuide「InterviewGuide」是阿秀从校园-职场多年计算机自学过程的记录以及学弟学妹们计算机校招秋招经验总结文章的汇总包括但不限于C/C 、Golang、JavaScript、Vue、操作系统、数据结构、计算机网络、MySQL、Redis等学习总结坚持学习持续成长项目地址https://gitcode.com/forthespada/InterviewGuide点击查看免费下载本文是「InterviewGuide」开源仓库中 LeetCode 树专题 Easy 题目笔记 的深度解读。围绕经典面试题「剑指 Offer 28. 对称的二叉树」从题目定义、对称性判定标准出发完整还原仓库笔记中记录的三种解法两种递归法、一种迭代法并结合仓库内 剑指 Offer 系列同题笔记 的另一种同思路实现帮你彻底吃透树的对称性判断这一高频考点。一、题目速览什么是一棵对称的二叉树原题出自力扣剑指 Offer 28. 对称的二叉树仓库笔记中给出了力扣原题链接对应牛客网版本为 No58、对称的二叉树收录于 剑指 Offer 全集。题目要求请实现一个函数用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样那么它是对称的。对称的含义一棵二叉树对称等价于这棵树和它的镜像完全相同。注意这里的镜像指的是水平翻转后的树而不是单纯的左右子树值相等——它要求左子树的左孩子 与 右子树的右孩子对应、左子树的右孩子 与 右子树的左孩子对应逐层、逐节点镜像相等。1. 对称的例子例如二叉树[1,2,2,3,4,4,3]是对称的1 / \ 2 2 / \ / \ 3 4 4 3从根节点1出发左子树根2与右子树根2值相等再往下一层左子树的左孩子3与右子树的右孩子3对应左子树的右孩子4与右子树的左孩子4对应完全镜像匹配。2. 不对称的例子而下面这个[1,2,2,null,3,null,3]则不是镜像对称的1 / \ 2 2 \ \ 3 3虽然两个子树根节点都是2但左子树缺失了左孩子、只有右孩子3右子树缺失了右孩子、只有左孩子3。若按镜像规则左子树的左孩子应当与右子树的右孩子对应此处却是null对null表面匹配而左子树的右孩子3应当与右子树的左孩子对应——右子树却没有左孩子位置错位导致不对称。这也是迭代法中需要格外警惕的值相等但位置不对陷阱。3. 示例与限制示例 1输入root [1,2,2,3,4,4,3] 输出true示例 2输入root [1,2,2,null,3,null,3] 输出false限制0 节点个数 1000注意节点个数可能为 0即空树root nullptr。从对称性的定义看空树没有左右子树需要比对视为对称返回true。二、核心思路把一棵树的对称转化为两棵子树的镜像相等判断整棵树是否对称本质上是一个双指针比较问题我们并不比较同一个节点的左右孩子那是左右子树相等不是对称而是比较根节点的左子树 与 右子树是否互为镜像。为此需要抽象出一个辅助函数isEqual(node1, node2)它的语义是判断以 node1 为根的树 与 以 node2 为根的树 是否互为镜像。判断规则只有三条两棵子树都为空nullptr与nullptr互为镜像返回true两棵子树一空一非空结构都不匹配返回false两棵子树都不空先比较当前节点值node1-val node2-val值相等后再递归判断node1的左孩子与node2的右孩子镜像对应、node1的右孩子与node2的左孩子镜像对应两者同时成立才返回true。主函数isSymmetric(root)只需处理空树然后调用isEqual(root-left, root-right)即可。下面仓库笔记中记录的三种写法都是在这个框架下展开的。三、解法一递归法基础版这是仓库笔记中给出的第一种实现逻辑最直白、最适合面试时先讲清楚思路bool isEqual(TreeNode* node1, TreeNode* node2) { if (node1 nullptr node2 nullptr) return true; if (node1 nullptr node2 ! nullptr) return false; if (node2 nullptr node1 ! nullptr) return false; if (node1-val node2-val) { return isEqual(node1-left, node2-right) isEqual(node1-right, node2-left); } else return false; } bool isSymmetric(TreeNode* root) { if (root nullptr) return true; return isEqual(root-left, root-right); }逐行解读第一行判断双空这是递归的终止条件之一比较到叶子之下的nullptr层两侧都是空说明此前所有路径都镜像匹配返回true第二、三行分别处理node1 空但 node2 非空node2 空但 node1 非空两种情况只要一侧为空另一侧不为空结构就不对称直接返回false第四行两侧节点都存在且值相等才继续向下比较值不相等则返回false递归式isEqual(node1-left, node2-right) isEqual(node1-right, node2-left)是对称判定的灵魂左对右、右对左正是镜像二字的代码化表达。具备短路特性左侧一旦返回false右侧就不会再递归能提前剪枝。复杂度分析每个节点至多被访问一次时间复杂度 O(n)n 为节点个数题目限制 0 n 1000递归深度取决于树高最坏情况下退化成链为 O(n)空间复杂度 O(n)平均情况下为 O(log n)。仓库笔记中该实现的实测表现为执行用时 12 ms在所有 C 提交中击败了 32.98% 的用户内存消耗 16.3 MB击败 100.00% 的用户该数据为笔记作者提交当时的 LeetCode 环境实测仅作参考不同时期提交结果会有波动。四、解法二递归法精简改进版基础版的空判断写了三行其实可以合并。仓库笔记中的第二种写法把一空一非空两种情况合并成一行代码更紧凑bool isEqual(TreeNode* node1, TreeNode* node2) { if (node1 nullptr node2 nullptr) return true; if (node1 nullptr || node2 nullptr) return false; // 减少判断 if (node1-val node2-val) { return isEqual(node1-left, node2-right) isEqual(node1-right, node2-left); } else return false; } bool isSymmetric(TreeNode* root) { if (root nullptr) return true; return isEqual(root-left, root-right); }改进点分析if (node1 nullptr || node2 nullptr) return false;一行同时覆盖了基础版中两个分支前面已经排除了双空因此走到这一行时只要有一侧为空必然是一空一非空直接返回false即可其余逻辑与解法一完全一致但分支更少、判断次数更少代码可读性和执行效率都略有提升。仓库笔记中该实现的实测表现为执行用时 8 ms在所有 C 提交中击败了 67.83% 的用户内存消耗 16.4 MB击败 100.00% 的用户。这个精简版在仓库的剑指 Offer 系列笔记 58-剑指offer.md 中还有一次同思路的强化——二刷时作者进一步把值不相等提前返回代码更为紧凑bool isEqual(TreeNode* node1, TreeNode* node2) { if (node1 nullptr node2 nullptr) return true; if (node1 nullptr || node2 nullptr) return false; if (node1-val ! node2-val) return false; return isEqual(node1-left, node2-right) isEqual(node1-right, node2-left); } bool isSymmetrical(TreeNode* pRoot) { if (pRoot nullptr) return true; return isEqual(pRoot-left, pRoot-right); }可见在牛客网版本的isSymmetrical中作者将值不等用!直接短路返回减少了if/else嵌套层级。两处实现相互印证无论力扣版还是牛客版递归判对称的骨架完全一致差别仅在空判断与值判断的写法组织上。这也是递归类二叉树题最常见的面试演进路径——先把思路讲对再谈精简。五、解法三迭代法借助队列按层比对递归之外仓库笔记还记录了一种迭代实现。思路是利用队列做层序遍历把每一层所有节点的左右孩子包括空指针收集进一个临时数组然后从数组两端向中间做镜像比对。作者在笔记中标注太麻烦了不值得借鉴但它对理解值相等但结构不对称的边界情况非常有帮助面试时也可以作为递归之外我还会迭代的能力展示。bool isSymmetric(TreeNode* root) { if (!root) { return true; } queueTreeNode * que1; que1.push(root); while (!que1.empty()) { int size que1.size(); vectorTreeNode * tmp; // 判断虽然不是镜像节点但是值依然相等的情况比如上述情况 while (size 0) { TreeNode *fronts que1.front(); que1.pop(); tmp.push_back(fronts-left); if (fronts-left) { que1.push(fronts-left); } tmp.push_back(fronts-right); if (fronts-right) { que1.push(fronts-right); } size--; } int i 0; int j tmp.size() - 1; while (i j) { if (tmp[i] ! nullptr tmp[j] ! nullptr) { if (tmp[i]-val ! tmp[j]-val) { return false; } } else if (tmp[i] nullptr tmp[j] nullptr) { // 两侧都为空继续比较下一对 } else { return false; } i; j--; } } return true; }执行流程拆解空树直接返回true把根节点入队进入层序遍历外层循环记录当前层节点数size内层循环逐一出队并把每个节点的left、right原样包括 nullptr压入临时数组tmp同时把非空孩子重新入队供下一层使用。这一步的关键是空指针也要占位否则下一层无法从位置上做镜像比对本层收集完毕后用双指针i、j从tmp两端向中间扫描两侧都非空则比val值不等返回false一空一非空返回false双空则继续所有层都通过比对最终返回true。为什么需要临时数组 tmp笔记注释点出了要害判断虽然不是镜像节点但是值依然相等的情况。例如题目中的反例1 / \ 2 2 \ \ 3 3第二层的两个孩子都是2值相等但如果只比这一层从左到右的值序列[2,2]本身是对称的会误判为对称。只有把第三层的空位也纳入左子树的左孩子为null、右子树的左孩子为null序列为[null,3,null,3]才能发现tmp[0]与tmp[3]是空对非空从而正确判为不对称。这正是迭代法相对递归法更繁琐、更容易踩坑的地方也是作者评价其太麻烦、不值得借鉴的原因。复杂度分析每个节点同样至多访问一次时间 O(n)需要队列与临时数组存储节点空间 O(n)。六、三种解法对比与面试建议维度解法一递归基础版解法二递归精简版解法三迭代法思路左右子树互为镜像递归比对同上合并空判断分支层序遍历 双指针镜像比对代码量较多三个空判断分支最少\|\|合并空判断最多队列 临时数组时间复杂度O(n)O(n)O(n)空间复杂度O(h)h 为树高O(h)h 为树高O(n)风险点分支冗余易写漏需理解\|\|前已排除双空空指针占位易错易误判值等位错作者评价直白易懂推荐太麻烦了不值得借鉴面试建议首选递归先讲清楚比较左子树的左孩子与右子树的右孩子、左子树的右孩子与右子树的左孩子这一镜像判定核心再给出解法二这种精简实现展示代码组织能力务必处理空树题目限制节点数可为 0root nullptr时返回true这一点仓库笔记与剑指 Offer 笔记两处实现都专门写了注释强调能讲清迭代作为加分项如果你能指出迭代法需要空指针占位 双指针比对并说明[1,2,2,null,3,null,3]这类反例为何会迷惑只看值的写法会让面试官确认你是真懂而不是背题横向关联对称判断与 面试题26.树的子结构、面试题07.重建二叉树 一样都属于树的递归结构比较家族掌握了递归比较两棵子树的范式这类题可以一通百通。七、仓库定位与延伸阅读本笔记收录于 InterviewGuide 仓库的 LeetCode 树专题 Easy 分类下同专题还整理了序列化二叉树、二叉树的前/中/后序遍历、二叉搜索树第 k 大节点等一系列高频树题本题的牛客网版本则位于 剑指 Offer 系列 No58两处解法可对照阅读。此外仓库的 02-sword-offer 目录收录了完整剑指 Offer 题解03-leetcode 目录则按专题整理了精选力扣题目适合校招、社招算法复习时系统刷题。核心结论回顾判断二叉树对称本质是判断左子树与右子树互为镜像递归解法用isEqual(node1-left, node2-right) isEqual(node1-right, node2-left)一句话点破镜像关系迭代解法则通过层序收集 双指针比对处理值等位错的陷阱。从基础版到精简版再到迭代版这一题完整覆盖了二叉树递归比较问题的思考路径值得作为树专题的入门必刷题反复咀嚼。赞分享文档教程知识库【免费下载链接】InterviewGuide「InterviewGuide」是阿秀从校园-职场多年计算机自学过程的记录以及学弟学妹们计算机校招秋招经验总结文章的汇总包括但不限于C/C 、Golang、JavaScript、Vue、操作系统、数据结构、计算机网络、MySQL、Redis等学习总结坚持学习持续成长项目地址https://gitcode.com/forthespada/InterviewGuide点击查看免费下载相关推荐StarRocks CORR 函数实战计算两列数据的皮尔逊相关系数StarRocks CORR 函数实战计算两列数据的皮尔逊相关系数 StarRocks 的 CORR 聚合函数用于计算两个表达式之间的皮尔逊相关系数Pear教程InterviewGuide 刷题笔记剑指 Offer 28「对称的二叉树」递归与迭代全解法剖析InterviewGuide 刷题笔记剑指 Offer 28「对称的二叉树」递归与迭代全解法剖析 本篇是 InterviewGuide 仓库中「 精选力扣 3文档教程知识库Eclipse Mosquitto 0.8.2 缺陷修复版本深度解析loop 超时、消息队列与 QoS 重试逻辑Eclipse Mosquitto 0.8.2 缺陷修复版本深度解析loop 超时、消息队列与 QoS 重试逻辑 Mosquitto 0.8.2 是 Ecli教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

openJiuwen agent-core ByModelNameAllocator 状态序列化重构:从 dict 到 list 的兼容演进

openJiuwen agent-core ByModelNameAllocator 状态序列化重构:从 dict 到 list 的兼容演进

人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习 【免费下载链接】agent-core openJiuwen agent-core可提供AI Agent开发、运行、调优与演进相关的全套SDK能力 项目地址: https://gitcode.com/openJiuwen/agent-core 点击查看 免费下载 导读 本文聚…

2026/10/12 22:18:41 阅读更多 →
Splash模型怎么选:GGUF、MLX 4-bit与NVFP4量化格式完整选型指南(24GB内存Mac必读)

Splash模型怎么选:GGUF、MLX 4-bit与NVFP4量化格式完整选型指南(24GB内存Mac必读)

【免费下载链接】splash A local inference engine for Apple silicon, built around the model. 项目地址: https://gitcode.com/gh_mirrors/splash20/splash 点击查看 免费下载 Splash 是一款专为 Apple silicon 打造的本地推理引擎,让你在一台 Mac 上…

2026/10/12 22:18:41 阅读更多 →
Cppcheck嵌入式静态分析实战:从代码缺陷到CI门禁

Cppcheck嵌入式静态分析实战:从代码缺陷到CI门禁

1. 为什么嵌入式项目需要静态分析1.1 嵌入式代码的痛苦来源做嵌入式开发的朋友,大概都有过这样的经历:代码在本地编译时一切正常,烧进芯片跑几小时甚至几天后,系统莫名死机;或者某个功能在特定输入下才偶发出错&#x…

2026/10/12 22:18:40 阅读更多 →

最新新闻

Java 设计模式之 Template View:用模板视图分离静态布局与动态内容,打造可复用网页渲染骨架

Java 设计模式之 Template View:用模板视图分离静态布局与动态内容,打造可复用网页渲染骨架

示例工程教程 【免费下载链接】java-design-patterns Design patterns implemented in Java 项目地址: https://gitcode.com/GitHub_Trending/ja/java-design-patterns 点击查看 免费下载 导读:Template View(模板视图)是一种面向…

2026/10/14 2:05:18 阅读更多 →
电力弹簧技术在主动配电网中的关键应用与优化

电力弹簧技术在主动配电网中的关键应用与优化

1. 电力弹簧技术背景与配电网痛点电力弹簧(Electric Spring)作为第三代柔性电力电子装置,本质上是一种具备快速响应能力的电压/电流双模式补偿器。与传统STATCOM、SVG等无功补偿设备相比,其独特之处在于能够通过智能控制算法主动调…

2026/10/14 2:05:18 阅读更多 →
OpenClaw 会话工具(Session Tools)完全指南:sessions_list / sessions_history / sessions_send / sessions_spawn

OpenClaw 会话工具(Session Tools)完全指南:sessions_list / sessions_history / sessions_send / sessions_spawn

人工智能大模型LLM 网关AI Agent即时通讯 【免费下载链接】openclaw-zero-token OpenClaw: Use All Major AI Models NO API Token! Claude/ChatGPT/Gemini/DeepSeek/Doubao/Grok/Qwen/Manus/Kimi 项目地址: https://gitcode.com/gh_mirrors/op/openclaw-zero-token…

2026/10/14 2:05:18 阅读更多 →
T3 Stack实战:t3code如何实现端到端类型安全的全栈开发

T3 Stack实战:t3code如何实现端到端类型安全的全栈开发

t3code 这个名字,乍一看确实有点抽象。但如果你这几年一直混在 Next.js 和 TypeScript 的圈子里,看到 t3 前缀,大概率会想到那个火得一塌糊涂的 T3 Stack——Next.js、TypeScript、tRPC、Prisma、Tailwind 再加上 NextAuth 的组合。t3code 其…

2026/10/14 2:05:18 阅读更多 →
仓颉框架 CJoy 配置模块测试设计:从 config-tests 规格到测试用例实现

仓颉框架 CJoy 配置模块测试设计:从 config-tests 规格到测试用例实现

后端Web框架MCP 服务 【免费下载链接】cjoy 一个高性能、可扩展、轻量、省心的仓颉应用开发框架。IoC,Rest,宏路由,Json,中间件,参数绑定与校验,文件上传下载,OAuth2,MCP...... 项目…

2026/10/14 2:05:18 阅读更多 →
voidImageViewer 项目内 WebP 规范文档生成指南:用 kramdown 从 Markdown 文本源构建 Container Spec HTML

voidImageViewer 项目内 WebP 规范文档生成指南:用 kramdown 从 Markdown 文本源构建 Container Spec HTML

桌面应用图像处理 【免费下载链接】voidImageViewer Lightweight image viewer for Windows with animated GIF/WEBP support 项目地址: https://gitcode.com/gh_mirrors/vo/voidImageViewer 点击查看 免费下载 本篇技术指南讲解 voidImageViewer 仓库所集成的 lib…

2026/10/14 2:04:18 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/12 18:11:17 阅读更多 →