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

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


相关推荐
ting94520004 小时前
Humalike X Hermes 深度技术剖析:单指令注入群聊社交智能的底层架构、算法与跨 IM 平台实现
人工智能·算法·架构
吴声子夜歌5 小时前
Java面试——算法
java·算法·面试
evans在进步5 小时前
LeetCode 64:最小路径和——Java 原地动态规划详解
java·leetcode·动态规划
h_a_o777oah5 小时前
【图论】Tarjan 缩点:解决有向图中环的问题
c++·算法·图论·acm·强连通分量·缩点·tarjan
Tisfy5 小时前
LeetCode 1386.安排电影院座位:哈希表+位运算
算法·leetcode·散列表·题解·哈希表
Nil2086 小时前
leetcode 199二叉树的右视图
算法·leetcode·深度优先
M78佐菲7 小时前
c语言学习笔记:排序与查找方法整理
linux·c语言·笔记·学习·算法
AI备案指南-满满9 小时前
人工智能拟人化互动服务安全自评估报告的评估要点有哪些?
人工智能·算法·安全·机器人·大模型备案·算法备案
土司大王10 小时前
LeetCode hot100——两两交换链表中的节点
算法·leetcode·职场和发展