news 2026/9/16 10:56:38

翻转二叉树:LeetCode热题解析与实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
翻转二叉树:LeetCode热题解析与实现

1. 理解翻转二叉树问题

翻转二叉树是LeetCode热题HOT 100中的第226题,难度标记为简单,通过率高达82.5%。这道题要求我们将给定的二叉树进行左右翻转,也就是将每个节点的左右子树互换位置。

这个问题最初由计算机科学家Max Howell(Homebrew的作者)在Google面试时被问到,他当时没能写出这个算法,后来在Twitter上吐槽"Google: 90% of our engineers use the software you wrote (Homebrew), but you can't invert a binary tree on a whiteboard so fuck off." 这个趣闻让这道题在程序员圈子里变得非常有名。

2. 问题分析与解法思路

2.1 问题描述

给定一个二叉树的根节点root,翻转这棵二叉树,并返回其根节点。

示例: 输入:

4 / \ 2 7 / \ / \ 1 3 6 9

输出:

4 / \ 7 2 / \ / \ 9 6 3 1

2.2 递归解法

递归是最直观的解决方法,思路非常简单:

  1. 如果当前节点为空,直接返回
  2. 交换当前节点的左右子树
  3. 递归处理左子树
  4. 递归处理右子树
def invertTree(root): if not root: return None # 交换左右子树 root.left, root.right = root.right, root.left # 递归处理子树 invertTree(root.left) invertTree(root.right) return root

时间复杂度:O(n),每个节点都会被访问一次 空间复杂度:O(h),h是树的高度,递归调用栈的深度

2.3 迭代解法

对于不喜欢递归或者处理大深度树可能栈溢出的情况,可以使用迭代方法,通常使用队列或栈来实现广度优先或深度优先遍历。

使用队列的BFS实现:

from collections import deque def invertTree(root): if not root: return None queue = deque([root]) while queue: node = queue.popleft() # 交换左右子树 node.left, node.right = node.right, node.left # 将子节点加入队列 if node.left: queue.append(node.left) if node.right: queue.append(node.right) return root

使用栈的DFS实现:

def invertTree(root): if not root: return None stack = [root] while stack: node = stack.pop() # 交换左右子树 node.left, node.right = node.right, node.left # 将子节点压入栈 if node.left: stack.append(node.left) if node.right: stack.append(node.right) return root

3. 算法优化与变种

3.1 尾递归优化

对于支持尾递归优化的语言,可以改写递归版本为尾递归形式:

def invertTree(root): if not root: return None root.left, root.right = root.right, root.left invertTree(root.left) invertTree(root.right) return root

虽然Python不进行尾递归优化,但这种写法在其他语言中可能更高效。

3.2 并行处理优化

对于非常大的树,可以考虑并行处理左右子树:

from concurrent.futures import ThreadPoolExecutor def invertTree(root): if not root: return None root.left, root.right = root.right, root.left with ThreadPoolExecutor(max_workers=2) as executor: executor.submit(invertTree, root.left) executor.submit(invertTree, root.right) return root

注意:实际应用中需要考虑线程创建开销和GIL的影响。

4. 边界条件与测试用例

4.1 常见边界条件

  1. 空树:输入为None
  2. 只有根节点的树
  3. 只有左子树或只有右子树的树
  4. 完全二叉树
  5. 退化为链表的树(极度不平衡)

4.2 测试用例设计

import unittest class TestInvertTree(unittest.TestCase): def test_empty_tree(self): self.assertIsNone(invertTree(None)) def test_single_node(self): root = TreeNode(1) inverted = invertTree(root) self.assertEqual(inverted.val, 1) self.assertIsNone(inverted.left) self.assertIsNone(inverted.right) def test_full_tree(self): # 构造测试树 root = TreeNode(4) root.left = TreeNode(2) root.right = TreeNode(7) root.left.left = TreeNode(1) root.left.right = TreeNode(3) root.right.left = TreeNode(6) root.right.right = TreeNode(9) # 翻转 inverted = invertTree(root) # 验证 self.assertEqual(inverted.val, 4) self.assertEqual(inverted.left.val, 7) self.assertEqual(inverted.right.val, 2) self.assertEqual(inverted.left.left.val, 9) self.assertEqual(inverted.left.right.val, 6) self.assertEqual(inverted.right.left.val, 3) self.assertEqual(inverted.right.right.val, 1)

5. 实际应用场景

翻转二叉树虽然看似简单,但在实际开发中有多种应用场景:

  1. 图像处理:某些图像处理算法使用二叉树表示像素关系,翻转可以产生镜像效果
  2. 数据转换:某些数据存储格式需要左右子树交换
  3. 游戏开发:场景树的镜像生成
  4. 编译器优化:抽象语法树的变换

6. 常见错误与调试技巧

6.1 常见错误

  1. 忘记处理空节点导致NullPointerException
  2. 在递归前交换子树导致遍历错误
  3. 迭代实现时忘记将子节点加入队列/栈
  4. 修改了树结构但没有返回根节点

6.2 调试技巧

  1. 打印树结构辅助调试:
def printTree(root, level=0): if root: printTree(root.right, level + 1) print(' ' * 4 * level + '->', root.val) printTree(root.left, level + 1)
  1. 使用可视化工具如graphviz绘制二叉树

  2. 对于递归版本,可以添加递归深度打印:

def invertTree(root, depth=0): if not root: print(' ' * depth + 'None') return None print(' ' * depth + str(root.val)) root.left, root.right = root.right, root.left invertTree(root.left, depth + 1) invertTree(root.right, depth + 1) return root

7. 性能分析与优化

7.1 时间复杂度分析

所有解法的时间复杂度都是O(n),因为每个节点都会被访问一次。

7.2 空间复杂度分析

  1. 递归版本:O(h),h是树的高度,最坏情况O(n)
  2. 迭代版本:取决于使用的数据结构,最坏情况也是O(n)

7.3 实际性能考虑

  1. 对于平衡树,递归版本通常更快
  2. 对于极度不平衡的树,迭代版本更安全(避免栈溢出)
  3. Python中函数调用开销较大,对于小树递归版本可能更慢

8. 语言特性实现

8.1 Python特性实现

利用Python的多重赋值简化交换:

root.left, root.right = root.right, root.left

8.2 Java实现

public TreeNode invertTree(TreeNode root) { if (root == null) { return null; } TreeNode temp = root.left; root.left = invertTree(root.right); root.right = invertTree(temp); return root; }

8.3 JavaScript实现

function invertTree(root) { if (!root) { return null; } [root.left, root.right] = [invertTree(root.right), invertTree(root.left)]; return root; }

9. 扩展思考

9.1 部分翻转

如果题目改为只翻转某些特定节点(如值大于某个阈值的节点),如何修改算法?

def invertTreeIf(root, condition): if not root: return None if condition(root.val): root.left, root.right = root.right, root.left invertTreeIf(root.left, condition) invertTreeIf(root.right, condition) return root

9.2 翻转二叉树的应用

翻转二叉树实际上是二叉树对称操作的基础,可以用于:

  1. 检查二叉树是否对称
  2. 生成二叉树的镜像
  3. 某些平衡操作的前置步骤

10. 面试技巧

当面试中被问到翻转二叉树问题时:

  1. 先明确问题要求,确认输入输出
  2. 从最简单的递归解法开始
  3. 分析时间/空间复杂度
  4. 考虑边界条件
  5. 讨论迭代解法
  6. 如果有时间,讨论优化和变种

记住Max Howell的故事,这道题不仅是考算法,也是考察对二叉树的理解和编码能力。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 10:51:53

Rust内存安全加固实战:从所有权到FFI的完整指南

做系统级开发的朋友,应该都对“内存安全加固”这几个字不陌生。每次线上崩溃、每次被奇怪的缓冲区溢出搞得焦头烂额,我都会想:如果当时用的是一套能从编译器层面拦住这些错误的语言工具链,后面能少熬多少个通宵。这两年我花了不少…

作者头像 李华
网站建设 2026/9/16 10:50:24

Qwen3.5多模态大模型架构与PPIO平台部署实践

1. Qwen3.5技术架构与核心能力解析Qwen3.5作为阿里云最新推出的多模态大模型,其技术架构采用了混合专家系统(MoE)设计。基础层包含约700亿参数,通过动态路由机制实现不同任务场景下的专家模块组合调用。这种设计在保持模型规模的同…

作者头像 李华
网站建设 2026/9/16 10:50:15

大模型时代运维工程师转型AI架构师指南

1. 大模型时代下的运维工程师与AI架构师职业跃迁最近半年,我身边至少有5位传统运维工程师朋友成功转型为AI架构师,薪资涨幅普遍超过50%。这个现象并非偶然——大模型技术正在重塑整个IT职业生态。作为一位经历过从传统运维到云原生再到AI架构转型的从业者…

作者头像 李华
网站建设 2026/9/16 10:47:23

MAX30102与R7KA8D2KFLCAC构建可信血氧监测系统

1. 这不是“血氧仪DIY”,而是一套可复现的生理信号闭环监测系统你搜“MAX30102”出来的结果,90%是“手把手教你用Arduino测血氧”的入门帖——接线、烧录、串口打印一串数字,然后戛然而止。但真正做过连续72小时监护设备的人知道:…

作者头像 李华
网站建设 2026/9/16 10:45:32

MATLAB湍流数据可视化:从.mat加载到涡识别与论文级图像导出

简介:本资源是一份面向MATLAB初学者与图像处理入门者的实践型教学包,聚焦视频帧提取与基础图像处理技术,适用于高校课程实验、科研预处理任务及工程原型开发。压缩包共2个文件,含1个AVI视频(video1.avi)与1…

作者头像 李华
网站建设 2026/9/16 10:41:15

Pintos操作系统课设全攻略:从线程调度到虚拟内存

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

作者头像 李华