LeetCode递归实战:从斐波那契到链表反转,5个经典案例带你彻底搞懂递归

算法刷刷刷(一、递归) 去tm的封面 阅读详情

LeetCode递归实战:从斐波那契到链表反转,5个经典案例带你彻底搞懂递归

第一次接触递归时,很多人会被它那种"自我调用"的特性所迷惑——一个函数居然可以调用自己?这不会导致无限循环吗?直到我在LeetCode上刷到第50题时,才真正体会到递归的优雅与强大。记得当时为了理解汉诺塔问题的递归解法,我在白板上画了整整三页的调用栈示意图。本文将带你用五个经典案例,从基础到进阶,逐步拆解递归的思维模型。

1. 递归基础:斐波那契数列的启示

斐波那契数列是理解递归最经典的入门案例。这个数列的定义本身就带有递归特性:F(0)=0,F(1)=1,当n>1时,F(n)=F(n-1)+F(n-2)。这种"用自身定义自身"的特性,正是递归算法的天然应用场景。

def fib(n):
    if n <= 1:
        return n
    return fib(n-1) + fib(n-2)

这个简洁的实现完美诠释了递归三要素:

  1. 基准条件:当n≤1时直接返回n
  2. 递归调用:分解为fib(n-1)和fib(n-2)
  3. 组合结果:将子问题结果相加

但这段代码存在严重的性能问题——重复计算。以计算fib(5)为例:

fib(5)
├── fib(4)
│   ├── fib(3)
│   │   ├── fib(2)
│   │   │   ├── fib(1)
│   │   │   └── fib(0)
│   │   └── fib(1)
│   └── fib(2)
│       ├── fib(1)
│       └── fib(0)
└── fib(3)
    ├── fib(2)
    │   ├── fib(1)
    │   └── fib(0)
    └── fib(1)

提示:实际面试中,纯递归解法通常不是最优解,但理解这个原始版本对掌握递归思维至关重要。

2. 递归优化:记忆化与迭代转化

为了避免重复计算,我们可以引入**记忆化(Memoization)**技术。这是一种典型的"以空间换时间"策略:

memo = {0:0, 1:1}
def fib_memo(n):
    if n not in memo:
        memo[n] = fib_memo(n-1) + fib_memo(n-2)
    return memo[n]

这个优化版本的时间复杂度从O(2^n)降到了O(n),但空间复杂度升为O(n)。对于斐波那契数列,我们还可以进一步优化为迭代版本:

def fib_iter(n):
    if n <= 1:
        return n
    a, b = 0, 1
    for _ in range(2, n+1):
        a, b = b, a + b
    return b

三种实现方式的性能对比:

方法类型时间复杂度空间复杂度LeetCode执行时间
纯递归O(2^n)O(n)>1000ms
记忆化O(n)O(n)32ms
迭代O(n)O(1)28ms

3. 递归进阶:链表反转的艺术

链表反转是递归应用的另一个经典场景。相比迭代法需要维护三个指针,递归解法展现出惊人的简洁性:

def reverseList(head):
    if not head or not head.next:
        return head
    new_head = reverseList(head.next)
    head.next.next = head  # 关键步骤:让下一个节点指向自己
    head.next = None       # 断开原有连接
    return new_head

理解这段代码的关键在于想象递归栈的展开过程。假设链表为1→2→3→4→5:

  1. 递归到最深层时遇到节点5,满足基准条件直接返回
  2. 回到节点4的上下文,此时head=4,head.next=5
    • 执行head.next.next=head即5.next=4
    • 设置4.next=None断开原有连接
  3. 同理处理节点3、2、1
  4. 最终new_head始终指向原始链表的尾节点5

注意:链表类问题的递归解法通常需要更多的栈空间,对于超长链表可能导致栈溢出。

4. 递归实战:两两交换链表节点

LeetCode第24题要求两两交换链表中的节点,这比单纯反转更具挑战性。递归解法依然展现出清晰的逻辑结构:

def swapPairs(head):
    if not head or not head.next:
        return head
    first = head
    second = head.next
    first.next = swapPairs(second.next)  # 递归处理剩余部分
    second.next = first                  # 完成当前交换
    return second                        # 返回新的头节点

这个案例展示了递归处理局部结构+连接后续结果的典型模式。关键步骤解析:

  1. 保存当前节点和下一节点引用
  2. 当前节点的next指向递归处理后的剩余链表
  3. 下一节点的next指向当前节点
  4. 返回新的头节点(原第二个节点)

可视化过程(链表A→B→C→D):

swapPairs(A)
├── A.next = swapPairs(C)
│   ├── C.next = swapPairs(null) → return D
│   └── D.next = C → return D
└── B.next = A → return B
最终结果:B→A→D→C

5. 递归高阶:合并K个有序链表

当问题升级到合并K个有序链表时,递归结合分治策略展现出强大威力。这个问题是LeetCode上的困难题型,但递归解法依然保持优雅:

def mergeKLists(lists):
    if not lists:
        return None
    if len(lists) == 1:
        return lists[0]
    
    mid = len(lists) // 2
    left = mergeKLists(lists[:mid])    # 递归处理左半部分
    right = mergeKLists(lists[mid:])   # 递归处理右半部分
    return mergeTwoLists(left, right)  # 合并两个有序链表

def mergeTwoLists(l1, l2):
    if not l1:
        return l2
    if not l2:
        return l1
    if l1.val < l2.val:
        l1.next = mergeTwoLists(l1.next, l2)
        return l1
    else:
        l2.next = mergeTwoLists(l1, l2.next)
        return l2

这种分治策略的时间复杂度为O(NlogK),其中N是总节点数,K是链表数量。相比顺序合并的O(NK)有显著提升。算法流程解析:

  1. 基准情况处理:空列表或单链表
  2. 将链表列表分为两半
  3. 递归合并每一半
  4. 合并两个已排序链表

递归在算法领域展现出的这种"分而治之"特性,正是许多高效算法(如快速排序、归并排序)的核心思想。掌握递归思维,就等于拿到了一把解开复杂问题的万能钥匙。

kettle实验十一:没有数据流入时停止操作 【实验目的】 1.利用Kettle的“阻塞数据直到步骤都完成”,“检测空流”,“中止”等组件,实现Kettle转换流程的控制。 2.熟练掌握“阻塞数据直到步骤都完成”,“检测空流”,“中止”等组件的使用,实现Kettle转换流程的控制。 【实验原理】 “检测空流”组件可以检测所在转换的输入数据,如果整个转换没有输入数据,通过“中止”组件终止整个转换的流程。在存在数据输入的情况,为了能让数据输出,需要和“阻塞数据直到步骤都完成”配合使用。当所有数据都已经从上个步骤“字段选择”读取完毕后,通过“阻塞数据直到步骤 阅读详情

相关推荐

用 SQL 分析不同用户群组留存率

一、前言 用户增长对企业非常重要,主要包括: 新增、留存、召回 。本文介绍一个实用的分析留存率的方法: Cohort Analysis (群组分析),APP的下载量越高并不是说产品就越好,产品若没有很好的留存,花费大量时间和资源来挖掘新客户也将是竹篮打水一场空。群组分析有利于衡量用户在每个漏斗的用户流失节点、用户流失数据,从而帮助你发现产品的用户的行为模式和用户增长点。从本质上讲,群组分析Cohort Analysis为你提供了一种数据驱动的方法,用群组分析Cohort Analysis方法,可以来帮助提

qq_39984050的博客 3172

【LeetCode】十三、递归:斐波那契 + 反转链表

以hello为例,第一层递归,L = 0,R = 4,进入第二层递归,L = 1,R = 3,进入第三层递归,L= 2,R = 2,此时,触底,第三层递归函数执行return,结束,出栈。如上,第一层递归,L = 0,R = 4,但其传入下一层递归的L和R分别为1和3。这里以双指针的思想为基础,硬套一层递归来实现:还是L和r两个指针,递归终止的条件是 L >= r,递归的拆解则是每次L指针+1,r指针-1,递归要传递的参数不再是一个,而是L和 r 两个,上一层递归结束,回溯回来时,交换L和r位置的元素。

llg___的博客 1248

十三、FLUENT蒸发/冷凝模型实战:从沸腾模拟到常温蒸发的UDF进阶

本文深入探讨FLUENT蒸发/冷凝模型的应用实践,从沸腾模拟到常温蒸发的UDF进阶。通过分析相变模型的核心逻辑、关键陷阱及UDF动态饱和温度场的实现,帮助工程师准确模拟不同场景下的蒸发/冷凝过程。结合太阳能蒸馏器等工程案例,提供优化方案和常见问题解决方案,显著提升模拟精度与效率。

weixin_42548893的博客 571

java 链表反转 递归_递归法的理解——以反转链表为例

2020-01-07递归是什么:递归,从定义上说,指的是某个函数直接或者间接调用自己时,则发生了递归。比如说著名的斐波拉契数列的实现方法之一:1 public static int f(intn){23 if(n == 1 || n == 2) return 1;45 return f(n-1) + f(n-2);67 }在这个例子中,对于n大于2的情况,我们都直接调用f自身来递归...

weixin_29658015的博客 650

uniapp实战:mui-player插件如何完美适配m3u8/flv直播流(附完整代码)

本文详细介绍了如何在Uniapp中使用mui-player插件完美适配m3u8和flv直播流,提供从基础配置到高级优化的全流程解决方案。通过动态加载策略、响应式布局和内存管理,实现跨平台稳定播放,适用于企业级直播应用开发。

weixin_29001655的博客 236

精通DC-DC变换器:Boost升压电路全解析

Boost升压变换器是一种将低直流电压转换为高直流电压的常用电路。其核心工作原理是通过电感储能:开关导通时电感充电,关断时电感与电源串联向负载供电。关键公式表明输出电压Vo=Vi/(1-D),占空比D越大,升压比越高。变换器工作时会产生电感电流纹波和输出电压纹波,需合理选择电感和电容参数。开关管和二极管需承受完整的输出电压,对元器件选型要求较高。理解这些原理是设计高效升压电源的基础。

2511_92918351的博客 3707

Leetcode基础算法-递归算法

递龟?递归!

machenme的博客 683

【异常】Claude Code CLI 模型调用异常 There‘s an issue with the selected model (claude-sonnet-4-6). It may not

摘要: Claude Code CLI v2.1.45版本存在适配缺陷,导致调用claude-sonnet-4-6模型时触发"模型不存在"的误报错误(跨Windows/Linux平台)。该问题为版本回归类异常,非模型或账户权限问题。解决方案包括:1) 校验模型名称格式为claude-sonnet-4-6;2) 降级至v2.1.34或等待官方修复;3) 检查API配置有效性;4) 通过CLI交互界面手动选择模型;5) 临时切换同系列可用模型。官方已确认该bug并将发布修复版本。

奶爸的编程之路,也就一周冷个三天 6379

数据结构杂谈番外篇——搞懂递归的小文章

可以很好地帮助从未学过递归的人快速上手递归

弄鹊 596

innovus:如何在init design之后新增参考库(lib/lef)

如题,在PR过程中经常会遇到这种问题,时序无法收敛,需要新增一套lvt或者hpc的库,怎么办?

m0_61544122的博客 5007

【即插即用模块】注意力篇 | TIP 2024 | 注意力机制的有效改进!内容引导注意力块CGA,空间-通道-像素三个维度融合,实现涨点!

CGA(Content-Guided Attention)是一种融合多维度注意力的即插即用模块,通过并联空间和通道注意力并与像素注意力串联,实现从通道、空间到像素的三层级特征筛选。该模块采用层级递进设计,解决了传统单维度注意力的局限性,尤其适用于图像恢复等对特征精度要求高的任务。实验表明,CGA在去雾任务中能显著提升指标,但会略微增加参数量。模块代码支持灵活集成到各类视觉模型中,建议放置在网络靠前位置以充分释放后续层性能。其核心创新在于通过7×7大卷积捕捉长距离依赖,结合分组卷积实现像素级细粒度建模

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 227

递归1——递归入门算法题

从这章,我们先讲递归,然后讲搜索,然后再讲回溯算法。

2301_80224556的博客 1170

【系统架构设计师-2023年真题】综合知识-答案及详解

要实现多任务间的协同工作,操作系统必须提供任务间的通信手段。嵌入式操作系统一般都会提供多任务间通信的方法,其中()是任务间最直接、最明显的通信方法,也是访问共享的数据结构,即不同的任务都可以访问同一地址空间。()作为一种更高级的通信方式,能够在同一处理器的各个任务间传递任意长度(理论上只受物理内存和机器字长限制)的信息。(1)A. 共享内存 B. Socket C. 消息传递 D. 信号量(2)A. 共享内存 B. Socket C. 消息传递 D. 信号量【答案】A、C关于星型拓扑结构,下列说法正确的是(

数据知道的博客 1万+

LeetCode刷题(链表&栈)

一、斐波那契数列 https://leetcode-cn.com/problems/fibonacci-number/. 题目描述: 斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) = 0, F(1) = 1 F(N) = F(N - 1) + F(N - 2), 其中 N ...

u010707262的博客 331

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

手把手带你刷Leetcode力扣 学习总结

文章目录1. 总体规划2. 算法复杂度2.1 时间复杂度2.2 空间复杂度3. 数据结构3.1 数组【Array】3.1.1 Python常用操作3.1.2 Java常用操作3.1.3 练习题3.2 链表【Linked List】3.2.1 Python常用操作3.2.2 Java常用操作3.2.3 练习题3.3 队列【Queue】3.3.1 Python常用操作3.3.2 Java常用操作3.3.3 练习题3.4 栈【Stack】3.4.1 Python常用操作3.4.2 Java常用操作3.4.3 练习

qq_39223444的博客 2853

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

wy的leetcode刷题记录_Day71

wy的leetcode刷题记录_Day71声明前言2487. 从链表中移除节点题目介绍思路代码收获509. 斐波那契数题目介绍思路代码收获给你一个链表的头节点 head。移除每个右侧有一个更大数值的节点。返回修改后链表的头节点 head。示例 1:> 输入:head = [5,2,13,3,8]输出:[13,8]解释:需要移除的节点是 5 ,2 和 3。> - 节点 13 在节点 5 右侧。节点 13 在节点 2 右侧。节点 8 在节点 3 右侧。

m0_54015435的博客 1047

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

7天带你全方位刷爆数据结构与算法,每天一道,高效刷题

很多算法小白初期刷题比较迷茫,不知道从何刷起从何入手,也不知道怎么使用LeetCode,这篇带你高效使用力扣,让刷题进大厂的路上不再迷茫!

SQY0809的博客 705

LeetCode刷题(七)——递归思维+滑动窗口

Day10 2020.07.31 1.reverse-string 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。 解法一:双指针 class Solution{ public: void reverseString(vector<char>& s) {

Eve12345678的博客 892

leetcode算法-递归

递归 函数直接或间接地调用自己。 生活中的例子 从前有座山的故事。 从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事:从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事:。。。 4个要素 接受的参数 返回值 递归终止条件 递归拆解:如何递归到下一层 斐波拉契数列 0,1,1,2,3,5,8… f(n) = f(n - 1) + f(n - 2),其中f(0) = 0,f(1) = 1 recursion(int n) { if(n < 2) return

Prayer96的博客 306

leetcode经典算法题

算法题 链表反转 将单链表的连接顺序反转过来 例: 输入:1->2->3->4->5 输出:5->4->3->2->1 使用两种方式解题 方法一:迭代 package nuc.zy.edu.day1; /** * @Author:皮皮 * @Date:2021/5/8 17:40 */ //01-链表反转-迭代 public class ReverseList { static class ListNode { //结点的

weixin_47733114的博客 778

数据结构和算法之【递归】

本文主要讲解了解决问题的一种方案-递归

weixin_43945238的博客 847

递归算法

递归算法(英语:recursion algorithm)在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法。递归式方法可以被用于解决很多的计算机科学问题,因此它是计算机科学中十分重要的一个概念。绝大多数编程语言支持函数的自调用,在这些语言中函数可以通过调用自身来进行递归。计算理论可以证明递归的作用可以完全取代循环,因此在很多函数编程语言(如Scheme)中习惯用递归来实现循环。 在递推阶段,必须要有终止递归的情况。 206. 反转链表 反转一个单链表。 示例:...

一剑曾当百万师 386

【刷题】初探递归算法 —— 消除恐惧

本文讲解了递归算法,以多道题目加以辅助讲解。一文让你理解递归算法,消除恐惧!!!

叫我龙翔的博客 1117

Python面试别再死记硬背了!用这5个经典算法题搞定LeetCode入门(附完整代码)

本文针对Python开发者,精选5个LeetCode经典算法题(斐波那契数列、快速排序、二分查找、链表反转、二叉树遍历),详细解析解题思路、代码实现和面试沟通技巧。通过实战案例帮助读者掌握算法核心概念,提升面试表现和日常开发能力,告别死记硬背的学习方式。

weixin_29091837的博客 230

为什么你学不会递归?谈谈我的经验_递归算法很难理解(1)

求 n!从这个例子可以看出,我们直接从问题边界 1!1!1!一层层自底向上组合结果也可以得到 n!n!n!的解,自顶向下拆分问题的过程显得没有必要。确实,对于对于这种原问题与子问题只是地减少一个问题规模的情况,确实是这样。但是对于很多稍微复杂一些的问题,原问题与子问题会构成一个树型的结构,这个时候就适合用递归解决,很难用递推解决。:该数列从 111 开始,每一项数字都是前面两项数字的和。

2401_84183726的博客 1258

C语言算法进阶——递归

菜鸟升阶之旅!

weixin_52109967的博客 526
上一篇: PyTorch DDP实战:多GPU训练时全局batch size的5个常见配置误区
下一篇: C语言 - Doxygen代码注释规范实战指南
秃然暴富
博客等级 码龄4年 549粉丝 1627原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值