(LeetCode-Hot100)226. 翻转二叉树

❌|✅|💡|📌 问题简介

LeetCode 226. 翻转二叉树

复制代码
题解github地址: https://github.com/swf2020/LeetCode-Hot100-Solutions

题目描述

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

💡 解题思路

翻转二叉树的本质是将每个节点的左右子树互换。我们可以采用以下两种主流方法:

方法一:递归(深度优先搜索 DFS)

  1. 终止条件 :如果当前节点为 null,直接返回。
  2. 交换左右子树:对当前节点,交换其左右子节点。
  3. 递归处理子树:对左子树和右子树分别进行翻转。
  4. 返回根节点

✅ 优点:代码简洁,逻辑清晰。

❌ 缺点:在极端不平衡树中可能导致栈溢出(但 LeetCode 测试用例通常不会触发)。

方法二:迭代(广度优先搜索 BFS / 层序遍历)

  1. 使用队列(或栈)存储待处理的节点。
  2. 每次从队列中取出一个节点,交换其左右子节点。
  3. 如果左/右子节点非空,则将其加入队列。
  4. 重复直到队列为空。

✅ 优点:避免递归调用栈,适用于极深树。

❌ 缺点:代码稍复杂,需额外空间维护队列。


💻 代码实现

java 复制代码
// Java 实现
class Solution {
    // 方法一:递归
    public TreeNode invertTree(TreeNode root) {
        if (root == null) return null;
        // 交换左右子树
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
        // 递归翻转左右子树
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }

    // 方法二:迭代(BFS)
    public TreeNode invertTreeIterative(TreeNode root) {
        if (root == null) return null;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            // 交换左右子节点
            TreeNode temp = node.left;
            node.left = node.right;
            node.right = temp;
            // 将非空子节点加入队列
            if (node.left != null) queue.offer(node.left);
            if (node.right != null) queue.offer(node.right);
        }
        return root;
    }
}
go 复制代码
// Go 实现
package main

// Definition for a binary tree node.
type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

// 方法一:递归
func invertTree(root *TreeNode) *TreeNode {
    if root == nil {
        return nil
    }
    // 交换左右子树
    root.Left, root.Right = root.Right, root.Left
    // 递归翻转
    invertTree(root.Left)
    invertTree(root.Right)
    return root
}

// 方法二:迭代(BFS)
func invertTreeIterative(root *TreeNode) *TreeNode {
    if root == nil {
        return nil
    }
    queue := []*TreeNode{root}
    for len(queue) > 0 {
        node := queue[0]
        queue = queue[1:]
        // 交换
        node.Left, node.Right = node.Right, node.Left
        // 入队非空子节点
        if node.Left != nil {
            queue = append(queue, node.Left)
        }
        if node.Right != nil {
            queue = append(queue, node.Right)
        }
    }
    return root
}

🎯 示例演示

root = [4,2,7,1,3,6,9] 为例:

原始树结构:

复制代码
     4
   /   \
  2     7
 / \   / \
1   3 6   9

翻转后:

复制代码
     4
   /   \
  7     2
 / \   / \
9   6 3   1

每一步递归或迭代都确保当前节点的左右子树被交换,最终整棵树完成翻转。


✅ 答案有效性证明

  • 正确性 :通过数学归纳法可证。
    • 基础情况:空树或单节点树,翻转后不变,正确。
    • 归纳假设:假设对高度 ≤ h 的树翻转正确。
    • 归纳步骤:对高度 h+1 的树,先交换左右子树(均为高度 ≤ h),再递归翻转,由归纳假设成立,整体正确。
  • 边界处理:空输入返回空,符合预期。
  • LeetCode 测试:所有测试用例通过。

📊 复杂度分析

方法 时间复杂度 空间复杂度 说明
递归(DFS) O(n) O(h) h 为树高,最坏 O(n),平均 O(log n)
迭代(BFS) O(n) O(w) w 为最大层宽,最坏 O(n)(完全二叉树最后一层)

其中 n 为节点总数。


🧠 问题总结

  • 核心思想:树的翻转 = 每个节点左右子树交换。
  • 递归是最直观解法,代码简洁且易于理解。
  • 迭代适用于栈空间受限场景,但 LeetCode 中递归通常足够。
  • 此题是理解树遍历与递归的经典入门题,常被用于面试(如 Max Howell 的著名梗:"Google: 90% of our engineers use the software you wrote (Homebrew), but you can't invert a binary tree on a whiteboard so fuck off.")。
  • 掌握此题有助于理解后续更复杂的树操作(如对称树、相同树、镜像等)。
相关推荐
yyjtx1 小时前
DHU上机打卡D27
c++·算法·图论
漂流瓶jz1 小时前
UVA-12569 树上的机器人规划(简单版) 题解答案代码 算法竞赛入门经典第二版
算法·图论·dfs·bfs·uva·算法竞赛入门经典第二版·11214
hwtwhy2 小时前
【情人节特辑】C 语言实现浪漫心形粒子动画(EasyX 图形库)
c语言·开发语言·c++·学习·算法
云淡风轻~窗明几净2 小时前
割圆术求Pi值的重新验证
数据结构·算法
陈天伟教授2 小时前
人工智能应用- 材料微观:01. 微观结构的重要性
人工智能·神经网络·算法·机器学习·推荐算法
芒克芒克2 小时前
深入浅出Java线程池(一)
java·开发语言
wuqingshun3141592 小时前
红黑树有哪些特征
java·开发语言·jvm
ValhallaCoder2 小时前
hot100-贪心
数据结构·python·算法·贪心算法
追风少年ii2 小时前
顶刊分享--由细菌-癌细胞相互作用决定的差异性肿瘤免疫
人工智能·算法·数据分析·空间·单细胞