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

LeetCode 101. 对称二叉树:递归与迭代的完美结合

LeetCode 101. 对称二叉树:递归与迭代的完美结合

问题描述

给定一个二叉树,检查它是否是镜像对称的。

示例 1:

输入:root = [1,2,2,3,4,4,3] 输出:true

示例 2:

输入:root = [1,2,2,null,3,null,3] 输出:false

算法原理

核心思路

对称二叉树的判断可以通过以下方法实现:

  1. 递归方法:判断左子树和右子树是否镜像对称。具体来说,需要判断:

    • 左子树的左节点与右子树的右节点是否对称
    • 左子树的右节点与右子树的左节点是否对称
  2. 迭代方法:使用队列来模拟递归过程,每次取出两个节点进行比较。

复杂度分析

  • 时间复杂度:O(n),其中 n 是二叉树的节点数。每个节点恰好被访问一次。
  • 空间复杂度
    • 递归方法:O(h),其中 h 是二叉树的高度。递归调用栈的深度最大为 h。
    • 迭代方法:O(n),最坏情况下,队列中最多同时存在 O(n) 个节点(例如,当二叉树是满二叉树时,最后一层的节点数约为 n/2)。

代码实现

递归方法

# Definition for a binary tree node. class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right class Solution: def isSymmetric(self, root: Optional[TreeNode]) -> bool: if not root: return True def is_mirror(left, right): # 如果两个节点都为空,返回 True if not left and not right: return True # 如果只有一个节点为空,返回 False if not left or not right: return False # 比较节点值,并递归比较子节点 return (left.val == right.val and is_mirror(left.left, right.right) and is_mirror(left.right, right.left)) return is_mirror(root.left, root.right)

迭代方法

from collections import deque # Definition for a binary tree node. class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right class Solution: def isSymmetric(self, root: Optional[TreeNode]) -> bool: if not root: return True # 初始化队列,将左右子节点入队 queue = deque([root.left, root.right]) while queue: # 取出两个节点进行比较 left = queue.popleft() right = queue.popleft() # 如果两个节点都为空,继续循环 if not left and not right: continue # 如果只有一个节点为空,返回 False if not left or not right: return False # 如果节点值不相等,返回 False if left.val != right.val: return False # 将左子树的左节点和右子树的右节点入队 queue.append(left.left) queue.append(right.right) # 将左子树的右节点和右子树的左节点入队 queue.append(left.right) queue.append(right.left) return True

代码解析

递归方法

  1. 边界处理:如果根节点为None,返回True
  2. 辅助函数定义:定义一个is_mirror函数,用于判断两个子树是否镜像对称。
  3. 递归终止条件
    • 如果两个节点都为空,返回True
    • 如果只有一个节点为空,返回False
  4. 递归比较:比较两个节点的值,并递归比较左子树的左节点与右子树的右节点,以及左子树的右节点与右子树的左节点。
  5. 调用辅助函数:调用is_mirror函数,判断根节点的左子树和右子树是否镜像对称。

迭代方法

  1. 边界处理:如果根节点为None,返回True
  2. 初始化队列:创建一个队列,并将根节点的左右子节点入队。
  3. 遍历队列
    • 取出两个节点进行比较。
    • 如果两个节点都为空,继续循环。
    • 如果只有一个节点为空,返回False
    • 如果节点值不相等,返回False
    • 将左子树的左节点和右子树的右节点入队,将左子树的右节点和右子树的左节点入队。
  4. 返回结果:如果队列遍历完成,返回True

实战技巧

选择合适的方法

  • 递归方法:代码简洁易懂,适用于大多数情况。
  • 迭代方法:避免了递归栈溢出的问题,适用于深度较大的二叉树。

边界条件处理

  • 空树:如果树为空,直接返回True
  • 单节点树:如果树只有一个节点,直接返回True

错误分析

常见错误

  1. 递归终止条件错误:忘记处理节点为None的情况,导致递归无法终止。
  2. 比较顺序错误:在递归比较时,没有正确比较左子树的左节点与右子树的右节点,以及左子树的右节点与右子树的左节点。
  3. 队列操作错误:在迭代方法中,队列的入队顺序错误,导致比较失败。

扩展思考

变种问题

  1. 二叉树的镜像:将二叉树转换为它的镜像。
  2. 二叉树的相同:判断两个二叉树是否相同。
  3. 二叉树的对称遍历:按照对称顺序遍历二叉树。

应用场景

对称二叉树的判断在以下场景中有着广泛的应用:

  • 树的结构判断:判断树的结构是否对称。
  • 树的遍历:对称遍历可以用于某些特殊的树操作。
  • 算法设计:对称思想在许多算法设计中都有应用。

个人实践感悟

最近在准备转正答辩,每天被各种算法题和合并冲突吓醒,救命!今天刷到这个经典的对称二叉树问题,突然想到刚实习时第一次写这个题的场景。当时我还不知道递归的正确终止条件,结果代码在测试用例 [1,2,2,null,3,null,3] 上失败了,被mentor嘲笑了一整天,麻了!

现在再看这个问题,其实关键在于正确的递归终止条件和比较顺序。需要同时比较左子树的左节点与右子树的右节点,以及左子树的右节点与右子树的左节点。这让我意识到,算法的学习真的是一个循序渐进的过程,从一无所知到熟练掌握,需要不断地练习和总结。

最后,分享一个小技巧:在面试中遇到对称问题,首先要想到递归实现,同时要注意正确的比较顺序。如果面试官要求非递归实现,再考虑使用队列来模拟递归过程。这就是大佬吗?我也要成为这样的人!

输入输出示例

输入输出示例 1

输入:

root = [1,2,2,3,4,4,3]

输出:

true
输入输出示例 2

输入:

root = [1,2,2,null,3,null,3]

输出:

false

结语:对称二叉树的判断是树算法中的经典问题,掌握它不仅有助于解决相关的LeetCode问题,也能帮助我们更好地理解递归和迭代的思想。希望这篇文章对大家有所帮助,祝大家刷题愉快!

http://www.jsqmd.com/news/542453/

相关文章:

  • 3个惊喜功能:让Markdown Viewer成为你浏览器的得力助手
  • NaViL-9B实战手册:图文问答+纯文本问答双路径使用指南
  • 硬盘健康监测工具DiskInfo:从基础监控到高级应用全指南
  • Spring_couplet_generation 使用ComfyUI?探讨不同WebUI框架的部署选择
  • 便携·快检·18.88万:金属3D打印应力检测门槛大幅降低
  • 如何从零构建自己的地震监测系统:10个核心模块实战指南
  • OWL ADVENTURE STM32嵌入式部署初探:将轻量模型移植到C8T6开发板
  • HP-Socket开发者职业发展路径图:从初级到高级网络通信专家的完整指南 [特殊字符]
  • 常用AI网站
  • 如何使用Uvicorn部署Google Cloud Functions Gen 2:打造高性能无服务器应用
  • Obsidian Sample Plugin 插件性能调优:内存管理与CPU使用优化
  • ADS 实战指南(十一):理想元件与库元件仿真差异的精准调优
  • Step3-VL-10B-Base与Node.js集成教程:构建多模态文件上传处理服务
  • Windows 11任务栏太反人类?用StartAllBack 3.6一键恢复Win10经典布局(附配置截图)
  • Deepfake Offensive Toolkit技术路线图风险评估矩阵:可能性与影响分析
  • el-table结合sortablejs实现行拖拽时禁止特定行移动
  • Windows下OpenClaw安装避坑:百川2-13B量化模型对接详解
  • 快速上手CosyVoice2:无需代码,网页操作,轻松克隆声音做配音
  • 别再乱接18650电池了!手把手教你DIY一个8V/5000mAh的移动电源(附电路图与安全要点)
  • VSCode + Cortex-Debug嵌入式调试全攻略:从settings.json到launch.json的完整配置流程
  • 给Unity萌新的C#版本选择指南:2024年新项目到底该用Unity哪个版本?
  • HP-Socket技术演讲视频描述撰写指南:关键词与吸引力
  • SoybeanAdmin国际化:多语言支持与本地化实践
  • Windows Insider计划离线管理命令行工具:安全切换与高效管理指南
  • SWF逆向工程认证考试复习指南:JPEXS Free Flash Decompiler重点整理
  • SEO_从零开始构建网站SEO体系的完整方案
  • Repomix CLI命令大全:所有参数选项详解
  • 如何为Rainmeter贡献多语言翻译:完整指南
  • 终极指南:如何使用Mermaid.js创建太空探索任务规划与系统架构图表
  • Linux exec进程替换详解