❌|✅|💡|📌 问题简介
题解github地址: https://github.com/swf2020/LeetCode-Hot100-Solutions
题目描述
给你一棵二叉树的根节点 root,翻转这棵二叉树,并返回其根节点。
📌 示例说明
示例 1:
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
示例 2:
输入:root = [2,1,3]
输出:[2,3,1]
示例 3:
输入:root = []
输出:[]
💡 解题思路
翻转二叉树的本质是将每个节点的左右子树互换。我们可以采用以下两种主流方法:
方法一:递归(深度优先搜索 DFS)
- 终止条件 :如果当前节点为
null,直接返回。 - 交换左右子树:对当前节点,交换其左右子节点。
- 递归处理子树:对左子树和右子树分别进行翻转。
- 返回根节点。
✅ 优点:代码简洁,逻辑清晰。
❌ 缺点:在极端不平衡树中可能导致栈溢出(但 LeetCode 测试用例通常不会触发)。
方法二:迭代(广度优先搜索 BFS / 层序遍历)
- 使用队列(或栈)存储待处理的节点。
- 每次从队列中取出一个节点,交换其左右子节点。
- 如果左/右子节点非空,则将其加入队列。
- 重复直到队列为空。
✅ 优点:避免递归调用栈,适用于极深树。
❌ 缺点:代码稍复杂,需额外空间维护队列。
💻 代码实现
java
// 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;
}
// 方法二:迭代(BFS)
public TreeNode invertTreeIterative(TreeNode root) {
if (root == null) return null;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
// 交换左右子节点
TreeNode temp = node.left;
node.left = node.right;
node.right = temp;
// 将非空子节点加入队列
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
return root;
}
}
go
// Go 实现
package main
// Definition for a binary tree node.
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
// 方法一:递归
func invertTree(root *TreeNode) *TreeNode {
if root == nil {
return nil
}
// 交换左右子树
root.Left, root.Right = root.Right, root.Left
// 递归翻转
invertTree(root.Left)
invertTree(root.Right)
return root
}
// 方法二:迭代(BFS)
func invertTreeIterative(root *TreeNode) *TreeNode {
if root == nil {
return nil
}
queue := []*TreeNode{root}
for len(queue) > 0 {
node := queue[0]
queue = queue[1:]
// 交换
node.Left, node.Right = node.Right, node.Left
// 入队非空子节点
if node.Left != nil {
queue = append(queue, node.Left)
}
if node.Right != nil {
queue = append(queue, node.Right)
}
}
return root
}
🎯 示例演示
以 root = [4,2,7,1,3,6,9] 为例:
原始树结构:
4
/ \
2 7
/ \ / \
1 3 6 9
翻转后:
4
/ \
7 2
/ \ / \
9 6 3 1
每一步递归或迭代都确保当前节点的左右子树被交换,最终整棵树完成翻转。
✅ 答案有效性证明
- 正确性 :通过数学归纳法可证。
- 基础情况:空树或单节点树,翻转后不变,正确。
- 归纳假设:假设对高度 ≤ h 的树翻转正确。
- 归纳步骤:对高度 h+1 的树,先交换左右子树(均为高度 ≤ h),再递归翻转,由归纳假设成立,整体正确。
- 边界处理:空输入返回空,符合预期。
- LeetCode 测试:所有测试用例通过。
📊 复杂度分析
| 方法 | 时间复杂度 | 空间复杂度 | 说明 |
|---|---|---|---|
| 递归(DFS) | O(n) | O(h) | h 为树高,最坏 O(n),平均 O(log n) |
| 迭代(BFS) | O(n) | O(w) | w 为最大层宽,最坏 O(n)(完全二叉树最后一层) |
其中
n为节点总数。
🧠 问题总结
- 核心思想:树的翻转 = 每个节点左右子树交换。
- 递归是最直观解法,代码简洁且易于理解。
- 迭代适用于栈空间受限场景,但 LeetCode 中递归通常足够。
- 此题是理解树遍历与递归的经典入门题,常被用于面试(如 Max Howell 的著名梗:"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.")。
- 掌握此题有助于理解后续更复杂的树操作(如对称树、相同树、镜像等)。