[从零开始面试算法] (11/100) LeetCode 226. 反转二叉树:递归的“镜像”魔法

引言

欢迎来到本系列的第十一篇!在我们通过“最大深度”问题初步领略了树的递归之美后,今天我们将面对一个更能体现递归“分治”思想的经典问题——LeetCode 226. 反转二叉树

这道题在面试界的地位非同凡响,它因 Homebrew 的作者 Max Howell 在 Google 面试时被这道题难住,并愤然发推吐槽而闻名于世。但这道题真的那么难吗?

当你第一次看到这道题,你可能会发现它具有一种“镜像”的对称性,并且可以分解成更小的、相同的问题。这正是解决它的正确方向!但如何将这种直觉转化为清晰、正确的代码呢?

本文将带你一起:

  1. 分析并完善关于“完全二叉树”、“终止条件”等问题的初步想法。

  2. 深入理解递归如何像一个“自上而下的命令链”,优雅地完成整棵树的反转。

  3. 掌握解决这类树结构修改问题的通用递归模板。


一、题目呈现

  • 题目编号:226. 反转二叉树

  • 题目难度:简单

  • 题目链接:226. 反转二叉树 - 力扣 (LeetCode)

  • 题目描述

    给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

  • 示例

    • 输入: root = [4,2,7,1,3,6,9]

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

    反转前:

          4/ \2   7/ \ / \1  3 6  9

反转后:

      4/ \7   2/ \ / \9  6 3  1

二、我的思考:递归直觉的打磨

这里完全采用你的笔记思路

看到这棵树,我的第一反应是:这个问题可以拆分成更小的相同问题。比如,要反转整棵以 4 为根的树,似乎可以先反转以 2 为根的左子树,再反转以 7 为根的右子树,最后再做点什么。这种“分治”的感觉,让我立刻想到了递归。

我的初步想法是:

  1. 终止条件:当递归到最左边的叶子节点,它的 left 是 nullptr 时,就应该停止了。

  2. 核心操作:在某个节点,我需要交换它的 left 和 right 指针,这需要一个临时变量来暂存。

但我很困惑:我应该按什么顺序去递归呢?先一路递归到最左边,再处理右边吗?那返回的顺序好像不对。而且,函数最后应该返回什么?是节点的值 val 吗?

你的思考过程非常棒!你已经抓住了递归交换这两个核心要素。现在,我们来逐一打磨这些想法,扫清困惑。

  1. 关于终止条件:只考虑 left 为 nullptr 是不够的。一个更通用、更安全的终止条件是:当递归遇到的当前节点 root 本身是 nullptr 时,就返回。因为我们不能对一个空节点做任何操作。

  2. 关于返回值:函数的签名是 TreeNode* invertTree(TreeNode* root),它要求我们返回一个 TreeNode* 指针。我们的任务是修改树的结构,并最终返回修改后整棵树的根节点

  3. 关于递归顺序:这正是本题的精髓!答案是,对于“反转”这个操作,先处理当前节点,再递归子节点(前序遍历) 的思路是最直观的。


三、豁然开朗:递归的“自顶向下”反转模型

让我们把反转过程想象成一个**“将军下令”**的指挥链。

将军(当前根节点 root)的任务只有两件:

  1. 先行动:交换自己直接指挥的两个师长(左子节点 left 和右子节点 right)的位置。

  2. 再下令:对换完位置的两位师长分别说:“现在,你们各自去把手下的部队(你们的子树)也全部反转一遍!”

这个命令会从最高级的将军 root,一层层地传递下去,直到最底层的士兵(叶子节点)。当士兵接到命令,发现自己手下没有兵(子节点为 nullptr)时,他什么也不做,直接报告“任务完成”。当所有士兵都报告完成后,整棵树的“镜像反转”就完成了。

C++ 最优代码与详解

这个“将军下令”的模型,可以被直接翻译成极其简洁的递归代码。

完整代码
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}* };*/
class Solution {
public:TreeNode* invertTree(TreeNode* root) {// 1.if (root == nullptr) {return nullptr;}// --- 核心操作区 (前序遍历位置) ---// 2.TreeNode* temp = root->left;root->left = root->right;root->right = temp;// 3.invertTree(root->left);invertTree(root->right);// 4.return root;}
};

代码逐点解释
  1. if (root == nullptr)
    递归的终止条件 (Base Case)。如果当前节点为空,它没有子节点可以交换,直接返回 nullptr。这是递归能够停止的保证。

  2. TreeNode* temp = ...;
    核心交换操作。我们先用一个临时指针 temp 暂存左子节点的地址,然后将右子节点赋给左指针,最后将暂存的地址赋给右指针,完成了对当前节点 root 的直接子节点的交换。

  3. invertTree(root->left); invertTree(root->right);
    分治与递归。这是“将军下令”的步骤。我们对已经交换过来的新左子树和新右子树,分别进行递归调用。我们完全信任这两个递归调用能完美地反转它们各自内部的所有结构。

  4. return root;
    返回结果。在完成了本层的交换和对子树的递归反转之后,当前 root 节点下的整棵子树都已经完成了反转。我们将这个 root 返回给它的上层调用。最终,最顶层的调用会返回整棵树的新根节点(其实还是原来的那个根节点,但它的结构已经被改变了)。


四、总结与收获

  • 复杂度分析:我们恰好访问了树中的每一个节点一次来执行交换操作。因此,时间复杂度为 O(n),其中 n 是节点的总数。递归调用栈的深度最坏情况下等于树的高度,因此空间复杂度为 O(h)

  • 核心思想:对于树这种具有天然递归结构的题目,分治思想是解决问题的金钥匙。将一个大问题(反转整棵树)分解为三个小步骤:处理当前节点递归处理左子树递归处理右子树

  • 关键技巧:理解递归函数调用的本质。当你写 invertTree(root->left) 时,你要在脑中形成一种“信任”——相信这个函数一定会返回一个已经完全反转好的左子树,而无需关心其内部细节。这种“定义与信任”是掌握递归的关键。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/95722.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/95722.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java设计模式之创建型—建造者模式

Java中最常用的设计模式-CSDN博客 “把对象的构造步骤拆成链式方法,调用者按需填参,最后一次性 build,避免构造函数爆炸。” 经典场景 参数多(>4 个)且大部分可选 需要不可变对象(final 字段&#xf…

网页计时器,支持多计时器管理、数据分享、用户数据同步、全屏展示等功能,可进行倒计时、正计时和显示世界时钟。

一个具有现代化 UI 和交互的计时器网页应用,支持多计时器管理、数据分享、用户数据同步、全屏展示等功能,可进行倒计时、正计时和显示世界时钟。它采用玻璃态设计和流畅动画效果,提供极佳的视觉体验。 特点: 支持多个计时器的创建…

纹理融合——用 TypeScript + Babylon.js 打造“可混合纹理序列”

我不想搞个一新的Shader,我就想用已有的材质(比如StandardMaterial和PBRMetallicRoughnessMaterial)实现纹理融合渐变等效果,于是我搞了一个TextureBlender。一、为什么重复造轮子?GPU 插值受限material.diffuseTextur…

【完整源码+数据集+部署教程】公交车部件实例分割系统源码和数据集:改进yolo11-fasternet

背景意义 随着城市化进程的加快,公共交通系统的需求日益增加,公交车作为城市交通的重要组成部分,其运行效率和安全性直接影响到城市的交通状况和居民的出行体验。因此,公交车的维护和管理显得尤为重要。在这一背景下,公…

【C++题解】关联容器

关于set,map以及变种 |关联容器| set&multiset | map&multimap |无序关联容器| Unordered set&multiset | Unordered map&multimap | 建议先了解之后再配合练习 这次练习CCF真题比较多,也比较基础,预计耗时不用这么久。 今天…

【智谱清言-GLM-4.5】StackCube-v1 任务训练结果不稳定性的分析

1. Prompt 我是机器人RL方向的博士生正在学习ManiSkill,在学习时我尝试使用相同命令训练同一个任务,但是我发现最终的 success_once 指标并不是相同的,我感到十分焦虑, 我使用的命令如下: python sac.py --env_id&qu…

MySQL 8.0 主从复制原理分析与实战

MySQL 8.0 主从复制原理分析与实战半同步复制设计理念:复制状态机——几乎所有的分布式存储都是这么复制数据的基于全局事务标识符(GTID)复制GTID工作原理多主模式多主模式部署示例课程目标: MySQL 复制(Replication&a…

[UT]记录case中seq.start(sequencer)的位置变化带来的执行行为的变化

现象: 代码选择打开57行,注释掉60行执行,结果58行不会打印。 代码选择打开60行,注释57行执行,结果58行正常打印。 sequence的执行需要时间!!! SV中代码57行切换到60行的区别&#xf…

利用keytool实现https协议(生成自签名证书)

利用keytool实现https协议(生成自签名证书)什么是https协议?https(安全超文本传输协议)是 HTTP 的安全版本,通过 SSL/TLS 加密技术,在客户端(如浏览器)和服务器之间建立加…

拆解 AI 大模型 “思考” 逻辑:从参数训练到语义理解的核心链路

一、引言:揭开 AI 大模型 “思考” 的神秘面纱​日常生活中的 AI 大模型 “思考” 场景呈现(如 ChatGPT 对话、AI 写作辅助、智能客服应答)​提出核心问题:看似具备 “思考” 能力的 AI 大模型,其背后的运作逻辑究竟是…

element plus 使用细节 (二)

接上一篇文章: element plus 使用细节 最近菜鸟忙于系统开发,都没时间总结项目中使用的问题,幸好还是在空闲之余总结了一点(后续也会来补充),希望能给大家带来帮助! 文章目录table fixed 的 v…

【机器学习学习笔记】numpy基础2

零基础小白的 NumPy 入门指南如果你想用电竞(打游戏)的思路理解编程:Python 是基础操作键位,而 NumPy 就是 “英雄专属技能包”—— 专门帮你搞定 “数值计算” 这类复杂任务,比如算游戏里的伤害公式、地图坐标&#x…

从自动化到智能化:家具厂智能化产线需求与解决方案解析

伴随着工业4.0浪潮和智能制造技术的成熟,家具行业正逐步从传统的自动化生产迈向智能化生产。智能化产线的构建不仅可以提升生产效率,还能满足个性化定制和柔性制造的需求。本文以某家具厂为例,详细解析智能化产线的核心需求,并提出…

macOS下基于Qt/C++的OpenGL开发环境的搭建

系统配置 MacBook Pro 2015 Intel macOS 12Xcode 14 Qt开发环境搭建 Qt Creator的下载与安装 在Qt官网的下载页面上下载,即Download Qt Online Installer for macOS。下载完成就得到一个文件名类似于qt-online-installer-macOS-x64-x.y.z.dmg的安装包。 下一步 …

当液态玻璃计划遭遇反叛者:一场 iOS 26 界面的暗战

引子 在硅谷的地下代码俱乐部里,流传着一个关于 “液态玻璃” 的传说 —— 那是 Apple 秘密研发的界面改造计划,如同电影《变脸》中那张能改变命运的面具,一旦启用,所有 App 都将被迫换上流光溢彩的新面孔。 而今天,我…

探究Linux系统的SSL/TLS证书机制

一、SSL/TLS证书的基本概念 1.1 SSL/TLS协议简介 SSL/TLS是一种加密协议,旨在为网络通信提供机密性、完整性和身份验证。它广泛应用于HTTPS网站、电子邮件服务、VPN以及其他需要安全通信的场景。SSL(安全套接字层)是TLS(传输层安全…

python和java爬虫优劣对比

Python和Java作为爬虫开发的两大主流语言,核心差异源于语法特性、生态工具链、性能表现的不同,其优势与劣势需结合具体场景(如开发效率、爬取规模、反爬复杂度)判断。以下从 优势、劣势、适用场景 三个维度展开对比,帮…

Unity 枪械红点瞄准器计算

今天突然别人问我红点瞄准器在镜子上如何计算,之前的吃鸡项目做过不记得,今天写个小用例整理下。 主体思想记得是目标位置到眼睛穿过红点瞄准器获取当前点的位置就可以。应该是这样吧,:) 武器测试结构 首先整个结构&am…

题解 洛谷P13778 「o.OI R2」=+#-

文章目录题解代码居然没有题解?我来写一下我的抽象做法。 题解 手玩一下,随便画个他信心的折线图,如下: 可以发现,如果我们知道终止节点,那么我们就可以知道中间有多少个上升长度。(因为它只能…

RTSP流端口占用详解:TCP模式与UDP模式的对比

在音视频传输协议中,RTSP(Real-Time Streaming Protocol,实时流传输协议)被广泛用于点播、直播、监控等场景。开发者在实际部署或调试时,常常会遇到一个问题:一路 RTSP 流到底占用多少个端口? 这…