题目描述
LeetCode 226. 翻转二叉树
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
示例 1:
text
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
示例 2:
text
输入:root = [2,1,3]
输出:[2,3,1]
示例 3:
text
输入:root = []
输出:[]
解题思路
翻转二叉树的核心思想是:对于每个节点,交换它的左右子树,然后递归或迭代地处理所有子节点。这道题虽然简单,但考察了对二叉树遍历的理解,也是很多面试的"热身题"。
解法一:递归(DFS,前序遍历)
思路
最直观的解法。对于当前节点 root:
-
交换它的左右子节点
-
递归翻转左子树
-
递归翻转右子树
这本质上是前序遍历的应用。
代码实现
java
class Solution {
public TreeNode invertTree(TreeNode root) {
// 递归终止条件:空节点直接返回
if (root == null) {
return null;
}
// 交换左右子节点
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
// 递归翻转左右子树
invertTree(root.left);
invertTree(root.right);
return root;
}
}
更简洁的写法:
java
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) return null;
TreeNode left = invertTree(root.left);
TreeNode right = invertTree(root.right);
root.left = right;
root.right = left;
return root;
}
}
复杂度分析
-
时间复杂度:O(n),n 为节点数,每个节点访问一次
-
空间复杂度:O(h),h 为树的高度,递归栈的深度
解法二:递归(后序遍历)
思路
也可以用后序遍历:先递归翻转左右子树,然后再交换当前节点的左右子节点。
代码实现
java
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) return null;
// 后序遍历:先处理子树
invertTree(root.left);
invertTree(root.right);
// 再交换当前节点的左右子节点
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
return root;
}
}
前序 vs 后序
| 遍历方式 | 区别 |
|---|---|
| 前序遍历 | 先交换当前节点,再处理子节点 |
| 后序遍历 | 先处理子节点,再交换当前节点 |
两者都能正确完成翻转,前序更符合"由上到下"的直觉,后序则体现了"由下到上"的思想。
解法三:迭代(BFS,层序遍历)
思路
使用队列进行层序遍历,逐层处理每个节点:将当前节点的左右子节点交换,然后将非空的子节点加入队列继续处理。
代码实现
java
import java.util.LinkedList;
import java.util.Queue;
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) return null;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode current = queue.poll();
// 交换当前节点的左右子节点
TreeNode temp = current.left;
current.left = current.right;
current.right = temp;
// 将子节点加入队列
if (current.left != null) {
queue.offer(current.left);
}
if (current.right != null) {
queue.offer(current.right);
}
}
return root;
}
}
复杂度分析
-
时间复杂度:O(n)
-
空间复杂度:O(n),队列在最坏情况下存储 n/2 个节点
解法四:迭代(DFS,前序遍历)
思路
使用栈模拟递归的前序遍历过程。
代码实现
java
import java.util.Stack;
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) return null;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode current = stack.pop();
// 交换左右子节点
TreeNode temp = current.left;
current.left = current.right;
current.right = temp;
// 先压右再压左,确保左子树先被处理(模拟前序遍历)
if (current.right != null) {
stack.push(current.right);
}
if (current.left != null) {
stack.push(current.left);
}
}
return root;
}
}
复杂度分析
-
时间复杂度:O(n)
-
空间复杂度:O(h),栈的深度
解法对比
| 解法 | 空间复杂度 | 优点 | 适用场景 |
|---|---|---|---|
| 递归(前序) | O(h) | 代码简洁,最直观 | 默认首选 |
| 递归(后序) | O(h) | 体现后序思想 | 学习意义 |
| BFS 迭代 | O(n) | 避免递归栈溢出 | 树很深时 |
| DFS 迭代 | O(h) | 空间优于 BFS | 树很深时 |
推荐:日常刷题用递归最简洁,面试中如果要求非递归可以用迭代版本。
经典梗:Max Howell 的故事
这道题之所以出名,很大程度是因为 2015 年 Homebrew 作者 Max Howell 在 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.
大意:Google 说"我们 90% 的工程师都用你写的软件,但你连翻转二叉树都写不出来,滚蛋吧。"
这个故事让这道题成为面试领域的"传奇",也提醒我们:不要因为基础题简单就忽视它,大神也会栽跟头 😂
扩展思考
-
对称二叉树(LeetCode 101):翻转后的树是否等于原树?
-
二叉树的镜像:翻转二叉树在图形学中也有应用
-
N 叉树的翻转:思路类似,将每个节点的子节点列表反转
总结
翻转二叉树的本质就是交换每个节点的左右子节点。无论是递归还是迭代,核心操作都是交换。
这道题看似简单,但考察了对二叉树遍历的掌握程度,也是很多公司面试的"试金石"。熟练掌握三种解法(递归、BFS、DFS),面试中就可以游刃有余。
题目链接 & 题解链接
-
题目链接 :LeetCode 226. 翻转二叉树
-
题解链接 :LeetCode 官方题解 - 翻转二叉树
如果这篇文章对你有帮助,欢迎点赞、收藏、关注!更多 LeetCode HOT 100 题解持续更新中~