拓冰建站拓冰建站
首页 / 资讯中心 / 正文

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

1. 理解翻转二叉树问题翻转二叉树是LeetCode热题HOT 100中的第226题难度标记为简单通过率高达82.5%。这道题要求我们将给定的二叉树进行左右翻转也就是将每个节点的左右子树互换位置。这个问题最初由计算机科学家Max HowellHomebrew的作者在Google面试时被问到他当时没能写出这个算法后来在Twitter上吐槽Google: 90% of our engineers use the software you wrote (Homebrew), but you cant 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 12.2 递归解法递归是最直观的解决方法思路非常简单如果当前节点为空直接返回交换当前节点的左右子树递归处理左子树递归处理右子树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 root3. 算法优化与变种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_workers2) as executor: executor.submit(invertTree, root.left) executor.submit(invertTree, root.right) return root注意实际应用中需要考虑线程创建开销和GIL的影响。4. 边界条件与测试用例4.1 常见边界条件空树输入为None只有根节点的树只有左子树或只有右子树的树完全二叉树退化为链表的树极度不平衡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. 实际应用场景翻转二叉树虽然看似简单但在实际开发中有多种应用场景图像处理某些图像处理算法使用二叉树表示像素关系翻转可以产生镜像效果数据转换某些数据存储格式需要左右子树交换游戏开发场景树的镜像生成编译器优化抽象语法树的变换6. 常见错误与调试技巧6.1 常见错误忘记处理空节点导致NullPointerException在递归前交换子树导致遍历错误迭代实现时忘记将子节点加入队列/栈修改了树结构但没有返回根节点6.2 调试技巧打印树结构辅助调试def printTree(root, level0): if root: printTree(root.right, level 1) print( * 4 * level -, root.val) printTree(root.left, level 1)使用可视化工具如graphviz绘制二叉树对于递归版本可以添加递归深度打印def invertTree(root, depth0): 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 root7. 性能分析与优化7.1 时间复杂度分析所有解法的时间复杂度都是O(n)因为每个节点都会被访问一次。7.2 空间复杂度分析递归版本O(h)h是树的高度最坏情况O(n)迭代版本取决于使用的数据结构最坏情况也是O(n)7.3 实际性能考虑对于平衡树递归版本通常更快对于极度不平衡的树迭代版本更安全避免栈溢出Python中函数调用开销较大对于小树递归版本可能更慢8. 语言特性实现8.1 Python特性实现利用Python的多重赋值简化交换root.left, root.right root.right, root.left8.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 root9.2 翻转二叉树的应用翻转二叉树实际上是二叉树对称操作的基础可以用于检查二叉树是否对称生成二叉树的镜像某些平衡操作的前置步骤10. 面试技巧当面试中被问到翻转二叉树问题时先明确问题要求确认输入输出从最简单的递归解法开始分析时间/空间复杂度考虑边界条件讨论迭代解法如果有时间讨论优化和变种记住Max Howell的故事这道题不仅是考算法也是考察对二叉树的理解和编码能力。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门