LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题

前言

二叉树是算法面试高频考点,而「翻转二叉树」是入门必刷的基础递归题。当年 Homebrew 作者面试谷歌,因不会写这道题被拒的段子更是让这道题火出圈。本文结合 LeetCode 原题,用 JavaScript 实现递归解法,逐行拆解思路,同时补充迭代拓展方案,看完彻底吃透二叉树递归分治思想。

一、题目信息

题目描述

给你一棵二叉树的根节点 root,翻转这棵二叉树,并返回其根节点。翻转二叉树的本质:树上每一个节点的左右子节点互相交换

样例演示

示例 1

输入数组:root = [4,2,7,1,3,6,9]原树结构:

plaintext

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

翻转后:

plaintext

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

输出数组:[4,7,2,9,6,3,1]

示例 2

输入:root = [2,1,3]原树:

plaintext

复制代码
  2
 / \
1   3

翻转后:

plaintext

复制代码
  2
 / \
3   1

输出:[2,3,1]

示例 3

输入空树 root = [],直接输出空树 []

标签分类

难度:简单考点:二叉树、深度优先搜索(DFS)、递归

二、递归解题思路

核心分治思想

我们可以把整棵树拆分成「根节点 + 左子树 + 右子树」三部分:

  1. 先把左子树完整翻转
  2. 再把右子树完整翻转
  3. 交换当前根节点的左右指针
  4. 递归终止条件:当前节点为null,没有子树,直接返回

通俗理解:自底向上处理,先把下层所有子树翻转完毕,再交换当前节点的左右分支。

完整 AC 代码(和截图完全对应)

javascript

运行

ini 复制代码
/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {TreeNode}
 */
var invertTree = function(root) {
    // 递归出口:空节点无需翻转
    if (!root) return root;

    // 递归翻转左右子树
    const left = invertTree(root.left);
    const right = invertTree(root.right);

    // 交换当前节点左右子节点
    root.left = right;
    root.right = left;

    return root;
};

三、逐行代码解析

  1. if (!root) return root;递归边界:如果遍历到空节点,不存在左右孩子,直接终止递归并返回自身。对应测试用例 3 空树的场景。
  2. const left = invertTree(root.left);递归进入左子树,拿到完全翻转完成后的左子树根节点
  3. const right = invertTree(root.right);递归进入右子树,拿到完全翻转完成后的右子树根节点

javascript

运行

ini 复制代码
root.left = right;
root.right = left;

核心操作:交换当前节点的左右指针,完成当前层节点的翻转。

  1. return root;把翻转完成的当前节点返回给上层父节点,供上层交换使用。

流程举例(示例 2 小树推演)

输入树 2 -> 左1、右3

  1. 执行invertTree(2),先递归invertTree(1)

    • 节点 1 左右都是 null,left=null、right=null,交换后还是 1,返回 1
  2. 再递归invertTree(3)

    • 节点 3 左右都是 null,交换后还是 3,返回 3
  3. 交换节点 2:left=3,right=1,返回 2,得到翻转后的树

四、复杂度分析

  • **时间复杂度 O (n)**n 为二叉树总节点数量,每个节点只会被递归访问、交换 1 次。

  • **空间复杂度 O (h)**h 代表二叉树高度,空间由递归调用栈占用:

    1. 平衡二叉树:树高 h = logn,空间复杂度 O (logn)
    2. 单边倾斜树(链式树):树高 h = n,空间复杂度 O (n)

五、拓展:BFS 层序迭代解法(规避递归栈溢出)

递归依赖调用栈,如果二叉树深度极大,会出现栈溢出报错。可以用队列实现广度优先迭代,逐层交换节点:

javascript

运行

ini 复制代码
var invertTree = function(root) {
    if (!root) return root;
    // 队列存储待处理节点
    const queue = [root];
    while (queue.length) {
        const node = queue.shift();
        // 交换当前节点左右
        [node.left, node.right] = [node.right, node.left];
        // 子节点入队,等待下一轮处理
        if (node.left) queue.push(node.left);
        if (node.right) queue.push(node.right);
    }
    return root;
};

思路:借助队列逐层遍历每一个节点,只要取出节点就交换左右,再把左右子节点放进队列循环处理。

六、补充:前序递归写法(先交换再递归)

上面代码是后序遍历(先处理子树,再交换当前节点),我们也可以先交换当前节点,再递归子树,逻辑等价:

javascript

运行

scss 复制代码
var invertTree = function(root) {
    if (!root) return root;
    // 先交换当前节点左右
    [root.left, root.right] = [root.right, root.left];
    // 再递归处理子树
    invertTree(root.left);
    invertTree(root.right);
    return root;
};

七、总结

  1. 翻转二叉树核心逻辑:每个节点交换左右子节点,递归分治处理整棵树;

  2. 递归固定模板三步:判空出口 → 递归处理左右子树 → 交换指针;

  3. 两种实现对比:

    • DFS 递归:代码极简,行数少,面试手写首选;
    • BFS 队列迭代:无调用栈溢出风险,适合深度极大的树;
  4. 这道题是二叉树递归的敲门砖,掌握交换左右节点的思路后,对称二叉树、二叉树镜像等同类题目都可以复用这套模板。

相关推荐
JieE2121 小时前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
kyriewen5 小时前
我用 AI 一周写完了整个项目,上线第一天就崩了——这是我踩过最贵的 5 个坑
前端·javascript·ai编程
Larcher6 小时前
AI Loop:让AI像人一样自主完成任务的核心机制
javascript·人工智能·设计模式
默_笙6 小时前
🃏 JS 只有 8 种数据类型,但我花了 2 天才搞懂 null 和 undefined 的区别
javascript
vivo互联网技术6 小时前
CVPR 2026 | 全新强化学习框架 BeautyGRPO:重塑真实人像
算法·大模型·cvpr·影像
jump_jump6 小时前
流式 HTML:从 htmx 片段装配到浏览器原生增量渲染
javascript·性能优化·前端工程化
Darling噜啦啦7 小时前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
swipe8 小时前
正则表达式入门到进阶:从表单校验到手写模板引擎
前端·javascript·面试