【力扣100题】28. 翻转二叉树

一、题目描述

给你一棵二叉树的根节点 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 = [] []

提示

  • 树中节点数目范围在 [0, 100]
  • -100 <= Node.val <= 100

二、解题思路

方法 核心思想 时间复杂度 空间复杂度
递归 前序遍历,交换左右子树 O(n) O(h),h为树高

核心公式

复制代码
翻转(root) = 交换左右子树 + 递归翻转左子树 + 递归翻转右子树

三、完整代码

cpp 复制代码
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) return root;              // 1. 空节点,直接返回
        TreeNode* left = invertTree(root->left);   // 2. 递归翻转左子树
        TreeNode* right = invertTree(root->right); // 3. 递归翻转右子树
        root->left = right;                         // 4. 交换左右子树
        root->right = left;
        return root;                                // 5. 返回根节点
    }
};

四、算法流程图

复制代码
以 root = [4,2,7,1,3,6,9] 为例:

翻转前:                翻转后:
    4                       4
   / \                     / \
  2   7      ────→        7   2
 /\  /\                  /\  /\
1 3 6 9                9 6 3 1

递归展开过程(自底向上):

    invertTree(4)
        │
        ├── invertTree(2) ──→ 返回2,左右交换后2不变
        │
        ├── invertTree(7) ──→ 返回7,左右交换后7不变
        │
        └── 交换4的左右子树:4->left=7, 4->right=2

详细展开:
    invertTree(4)
        ├── invertTree(2)
        │       ├── invertTree(1) ──→ return 1
        │       ├── invertTree(3) ──→ return 3
        │       └── 交换2的左右:2->left=3, 2->right=1 → return 2
        │
        ├── invertTree(7)
        │       ├── invertTree(6) ──→ return 6
        │       ├── invertTree(9) ──→ return 9
        │       └── 交换7的左右:7->left=9, 7->right=6 → return 7
        │
        └── 交换4的左右:4->left=7, 4->right=2 → return 4

五、逐行解析

cpp 复制代码
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        // ─────────────────────────────────────────
        // 第1步:递归终止条件
        // 空节点翻转后还是空,直接返回
        // ─────────────────────────────────────────
        if (root == NULL) return root;

        // ─────────────────────────────────────────
        // 第2步:递归翻转左子树
        // 子树翻转后赋值给left
        // 后续交换时会放到right的位置
        // ─────────────────────────────────────────
        TreeNode* left = invertTree(root->left);

        // ─────────────────────────────────────────
        // 第3步:递归翻转右子树
        // 子树翻转后赋值给right
        // 后续交换时会放到left的位置
        // ─────────────────────────────────────────
        TreeNode* right = invertTree(root->right);

        // ─────────────────────────────────────────
        // 第4步:交换左右子树
        // 原本的左子树放到右边
        // 原本的右子树放到左边
        // ─────────────────────────────────────────
        root->left = right;   // 左指针指向翻转后的右子树
        root->right = left;  // 右指针指向翻转后的左子树

        // ─────────────────────────────────────────
        // 第5步:返回翻转后的根节点
        // 供上层节点继续处理
        // ─────────────────────────────────────────
        return root;
    }
};

六、复杂度分析

时间复杂度

分析 复杂度
每个节点访问一次 O(n)

推导:n 个节点,每个节点处理一次(递归调用+交换)。

空间复杂度

分析 复杂度
函数调用栈,最大深度为树高h O(h)

推导

  • 最坏情况(链表形状):h = n,复杂度 O(n)
  • 平衡树情况:h = log n,复杂度 O(log n)

七、面试追问 FAQ

问题 回答
为什么用前序遍历? 前序遍历先处理根,再处理子树,适合这题自顶向下的交换
可以用中序或后序吗? 中序不行(会翻两次),后序可以
递归和迭代哪个更好? 递归代码简洁,迭代需要用栈模拟
翻转的本质是什么? 把每个节点的左右子树指针交换
如何用迭代实现? 层序遍历,访问每个节点时交换其左右子树

八、相关题目

题目 难度 关键点
226. 翻转二叉树 简单 本题
104. 二叉树的最大深度 简单 递归遍历
100. 相同的树 简单 递归比较
101. 对称二叉树 简单 翻转比较

九、总结

对比项 说明
代码行数 核心5行
时间复杂度 O(n)
空间复杂度 O(h)
递归顺序 前序遍历(根-左-右)
核心操作 交换左右子树指针

核心思想:把大树拆成小树,翻转左右子树,再交换回来。


相关推荐
故事和你911 小时前
洛谷-【数据结构2-2】线段树2
开发语言·数据结构·算法·动态规划·图论
ghie90901 小时前
MATLAB 随机蛙跳算法 (SFLA) 优化最小二乘回归
算法·matlab·回归
wuweijianlove1 小时前
算法优化中的缓存层次结构与内存映射的技术7
算法
故事和你911 小时前
洛谷-【数据结构2-2】线段树1
开发语言·javascript·数据结构·算法·动态规划·图论
电科一班林耿超1 小时前
机器学习大师课 第 8 课:端到端项目实战 —— 泰坦尼克号生存预测
人工智能·算法·机器学习
ComputerInBook1 小时前
数字图像处理(4版)——第 12 章——图像模式分类(上)(Rafael C.Gonzalez&Richard E. Woods)
图像处理·人工智能·算法·模式识别·图像模式分类
y = xⁿ1 小时前
20天速通LeetCodeday13:DFS深度优先搜素
算法·深度优先
七牛开发者2 小时前
开源项目观察|ds4:本地 Agent 推理,不只是把模型跑起来
人工智能·redis·算法·开源
影sir2 小时前
OI Wiki--算法竞赛百科
经验分享·算法