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

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


相关推荐
企业数字化笔记5 小时前
视频人体姿态怎么做三维可视化?2D关键点、深度局限与技术选型
人工智能·算法·音视频
?abc!6 小时前
(数组)581. 最短无序连续子数组
数据结构·算法·leetcode
小郎君6588 小时前
MPTT树复选框的半选状态:一棵百万节点树从递归到计数器,再到区间覆盖
算法
酌沧8 小时前
MemT让记忆成为模型内生能力
jvm·人工智能·算法
hold?fish:palm9 小时前
40 二叉树的直径
c++·leetcode
Shimeri9 小时前
越卷越像:我用遗传算法做了个"内卷"实验
算法·three.js·数据可视化·遗传算法·进化算法
Evand J10 小时前
【PMSM例程1】永磁同步电机(PMSM)转速与转子电角度观测算法|基于扩展卡尔曼滤波(EKF)的传感器状态估计与误差。附下载链接
算法·电机·1024程序员节·卡尔曼滤波
guo_wen_qiang10 小时前
二叉树的层序遍历-使用双端队列Deque
算法·leetcode·1024程序员节
爱读书的小胖10 小时前
LeetCode 55 跳跃游戏 C 语言解题分析
c语言·数据结构·算法·leetcode·1024程序员节
CCblandy10 小时前
前缀缓存命中率不靠引擎靠排列:本机仿真 3 轮,易变字段放开头 98.0%→0.0%
人工智能·python·算法·自然语言处理·性能优化