【力扣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)
递归顺序 前序遍历(根-左-右)
核心操作 交换左右子树指针

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


相关推荐
kisshyshy1 天前
🍦 雪糕、食堂、火车厢:三幅漫画吃透栈、队列与链表
javascript·算法
猿人谷1 天前
不只是 CPU 阈值:STAR 如何用 GAT + Transformer 做容器级自动扩缩容?
人工智能·算法
复杂网络1 天前
Stable Diffusion 视觉大模型微调技术深度调研
算法
复杂网络1 天前
基于 Stable Diffusion 架构的视觉大模型代表性工作与原理深度解析
算法
MrZhao4001 天前
Agent Loop 如何用 Hook 扩展:权限、日志与工具拦截
算法
MrZhao4001 天前
Agent 为什么需要 Skills:别把所有知识都塞进 system prompt
算法
JieE2123 天前
LeetCode 101. 对称二叉树|JS 递归 + 迭代双解法,彻底搞懂镜像判断
javascript·算法
JieE2124 天前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
Jack204 天前
HarmonyOS开发中错误处理策略:网络异常统一处理
算法
小小杨树4 天前
读懂色彩:拍照调色不再难
算法·计算机视觉·配色