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

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


相关推荐
tkevinjd8 小时前
416分割等和子集
java·python·算法·leetcode·职场和发展
Keven_118 小时前
算法札记:Tarjan与拓扑序(Topo)的关系
算法·拓扑·tarjan
ShallWeL9 小时前
AUC、F1、召回率怎么选
人工智能·算法·机器学习
水龙吟啸9 小时前
华为2026.6.3机考选择题+编程题【速刷敲黑板】
人工智能·深度学习·算法·华为
学究天人9 小时前
数学公理体系大全:第十四章 向量空间与模:线性代数的公理化与推广
线性代数·算法·矩阵·动态规划·抽象代数
zzz_236810 小时前
【Java实习面试算法冲刺】回溯
java·算法·面试
ysu_031418 小时前
05 | 持久化撤销提示非核心功能
算法·游戏程序
浮沉98719 小时前
二分查找算法概述&通用模板
算法
Keven_1120 小时前
算法札记:SPFA判负环算法的证明
算法
什巳20 小时前
JAVA练习278- 和为 K 的子数组
java·学习·算法·leetcode