递归的实战演练(入门级) | 算法必看系列五

简介: 通过实际题目(热身题&入门题)深入理解递归四步解题套路。

原文链接

一文学会递归解题

递归的实战演练(入门级)

热身赛

输入一个正整数n,输出n!的值。其中n!=123n,即求阶乘

套用上一节我们说的递归四步解题套路来看看怎么解:
1.定义这个函数,明确这个函数的功能,我们知道这个函数的功能是求 n 的阶乘, 之后求 n-1, n-2 的阶乘就可以调用此函数了

/**
 * 求 n 的阶乘
 */
public int factorial(int n) {
}

2.寻找问题与子问题的关系 阶乘的关系比较简单, 我们以 f(n) 来表示 n 的阶乘, 显然 f(n) = n * f(n - 1), 同时临界条件是 f(1) = 1,即
image.png
3. 将第二步的递推公式用代码表示出来补充到步骤 1 定义的函数中

/**
 * 求 n 的阶乘
 */
public int factorial(int n) {
    // 第二步的临界条件
    if (n < =1) {
        return1;
    }

    // 第二步的递推公式
    return n * factorial(n-1)
}

4.求时间复杂度 由于 f(n) = n f(n-1) = n (n-1) .... f(1),总共作了 n 次乘法,所以时间复杂度为 n。

看起来是不是有这么点眉目, 当然这道题确实太过简单,很容易套路,那我们再来看进阶一点的题。

入门题

一只青蛙可以一次跳 1 级台阶或一次跳 2 级台阶,例如:

跳上第 1 级台阶只有一种跳法:直接跳 1 级即可。跳上第 2 级台阶
有两种跳法:每次跳 1 级,跳两次;或者一次跳 2 级。
问要跳上第 n 级台阶有多少种跳法?

我们继续来按四步曲来看怎么套路。
1.定义一个函数,这个函数代表了跳上 n 级台阶的跳法

/**
 * 跳 n 极台阶的跳法
 */
public int f(int n) {
}

2.寻找问题与子问题之前的关系 这两者之前的关系初看确实看不出什么头绪,但仔细看题目,一只青蛙只能跳一步或两步台阶,自上而下地思考,也就是说如果要跳到 n 级台阶只能从 从 n-1 或 n-2 级跳, 所以问题就转化为跳上 n-1 和 n-2 级台阶的跳法了,如果 f(n) 代表跳到 n 级台阶的跳法,那么从以上分析可得 f(n) = f(n-1) + f(n-2),显然这就是我们要找的问题与子问题的关系,而显然当 n = 1, n = 2, 即跳一二级台阶是问题的最终解,于是递推公式系为

image.png
3.将第二步的递推公式用代码表示出来补充到步骤 1 定义的函数中 补充后的函数如下

/**
 * 跳 n 极台阶的跳法
 */
public int f(int n) {
    if (n == 1) return1;
    if (n == 2) return2;
    return f(n-1) + f(n-2)
}

4.计算时间复杂度 由以上的分析可知 f(n) 满足以下公式

image.png
斐波那契的时间复杂度计算涉及到高等代数的知识, 这里不做详细推导,有兴趣的同学可以点击这里查看,我们直接结出结论。
image.png
由些可知时间复杂度是指数级别,显然不可接受,那回过头来看为啥时间复杂度这么高呢,假设我们要计算 f(6),根据以上推导的递归公式,展示如下
image.png
可以看到有大量的重复计算, f(3) 计算了 3 次, 随着 n 的增大,f(n) 的时间复杂度自然呈指数上升了
5.优化
既然有这么多的重复计算,我们可以想到把这些中间计算过的结果保存起来,如果之后的计算中碰到同样需要计算的中间态,直接在这个保存的结果里查询即可,这就是典型的 以空间换时间,改造后的代码如下

public int f(int n) {
    if (n == 1) return1;
    if (n == 2) return2;
    // map 即保存中间态的键值对, key 为 n,value 即 f(n)
    if (map.get(n)) {
        return map.get(n)
    }
    return f(n-1) + f(n-2)
}

那么改造后的时间复杂度是多少呢,由于对每一个计算过的 f(n) 我们都保存了中间态 ,不存在重复计算的问题,所以时间复杂度是 O(n), 但由于我们用了一个键值对来保存中间的计算结果,所以空间复杂度是 O(n)。问题到这里其实已经算解决了,但身为有追求的程序员,我们还是要问一句,空间复杂度能否继续优化?
6.使用循环迭代来改造算法 我们在分析问题与子问题关系(f(n) = f(n-1) + f(n-2))的时候用的是自顶向下的分析方式,但其实我们在解 f(n) 的时候可以用自下而上的方式来解决,通过观察我们可以发现以下规律

f(1) = 1
f(2) = 2
f(3) = f(1) + f(2) = 3
f(4) = f(3) + f(2) = 5
....
f(n) = f(n-1) + f(n-2)

最底层 f(1), f(2) 的值是确定的,之后的 f(3), f(4) ,...等问题都可以根据前两项求解出来,一直到 f(n)。所以我们的代码可以改造成以下方式

public int f(int n) {
    if (n == 1) return1;
    if (n == 2) return2;

    int result = 0;
    int pre = 1;
    int next = 2;
    
    for (int i = 3; i < n + 1; i ++) {
        result = pre + next;
        pre = next;
        next = result;
    }
    return result;
}

改造后的时间复杂度是 O(n), 而由于我们在计算过程中只定义了两个变量(pre,next),所以空间复杂度是O(1)

简单总结一下:分析问题我们需要采用自上而下的思维,而解决问题有时候采用自下而上的方式能让算法性能得到极大提升,思路比结论重要。

递归的实战演练(进阶级)

来源 | 五分钟学算法
作者 | 码海

相关文章
|
3月前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
81 2
|
4月前
|
存储 缓存 算法
前端算法:优化与实战技巧的深度探索
【10月更文挑战第21天】前端算法:优化与实战技巧的深度探索
46 1
|
4月前
|
算法 搜索推荐 Shell
数据结构与算法学习十二:希尔排序、快速排序(递归、好理解)、归并排序(递归、难理解)
这篇文章介绍了希尔排序、快速排序和归并排序三种排序算法的基本概念、实现思路、代码实现及其测试结果。
81 1
|
5月前
|
大数据 UED 开发者
实战演练:利用Python的Trie树优化搜索算法,性能飙升不是梦!
在数据密集型应用中,高效搜索算法至关重要。Trie树(前缀树/字典树)通过优化字符串处理和搜索效率成为理想选择。本文通过Python实战演示Trie树构建与应用,显著提升搜索性能。Trie树利用公共前缀减少查询时间,支持快速插入、删除和搜索。以下为简单示例代码,展示如何构建及使用Trie树进行搜索与前缀匹配,适用于自动补全、拼写检查等场景,助力提升应用性能与用户体验。
86 2
|
4月前
|
算法 定位技术
数据结构与算法学习九:学习递归。递归的经典实例:打印问题、阶乘问题、递归-迷宫问题、八皇后问题
本文详细介绍了递归的概念、重要规则、形式,并展示了递归在解决打印问题、阶乘问题、迷宫问题和八皇后问题等经典实例中的应用。
72 0
|
2天前
|
算法 数据安全/隐私保护 计算机视觉
基于FPGA的图像双线性插值算法verilog实现,包括tb测试文件和MATLAB辅助验证
本项目展示了256×256图像通过双线性插值放大至512×512的效果,无水印展示。使用Matlab 2022a和Vivado 2019.2开发,提供完整代码及详细中文注释、操作视频。核心程序实现图像缩放,并在Matlab中验证效果。双线性插值算法通过FPGA高效实现图像缩放,确保质量。
|
1月前
|
算法 数据安全/隐私保护 计算机视觉
基于Retinex算法的图像去雾matlab仿真
本项目展示了基于Retinex算法的图像去雾技术。完整程序运行效果无水印,使用Matlab2022a开发。核心代码包含详细中文注释和操作步骤视频。Retinex理论由Edwin Land提出,旨在分离图像的光照和反射分量,增强图像对比度、颜色和细节,尤其在雾天条件下表现优异,有效解决图像去雾问题。
|
1月前
|
算法 数据可视化 安全
基于DWA优化算法的机器人路径规划matlab仿真
本项目基于DWA优化算法实现机器人路径规划的MATLAB仿真,适用于动态环境下的自主导航。使用MATLAB2022A版本运行,展示路径规划和预测结果。核心代码通过散点图和轨迹图可视化路径点及预测路径。DWA算法通过定义速度空间、采样候选动作并评估其优劣(目标方向性、障碍物距离、速度一致性),实时调整机器人运动参数,确保安全避障并接近目标。
147 68
|
1月前
|
算法 数据安全/隐私保护
室内障碍物射线追踪算法matlab模拟仿真
### 简介 本项目展示了室内障碍物射线追踪算法在无线通信中的应用。通过Matlab 2022a实现,包含完整程序运行效果(无水印),支持增加发射点和室内墙壁设置。核心代码配有详细中文注释及操作视频。该算法基于几何光学原理,模拟信号在复杂室内环境中的传播路径与强度,涵盖场景建模、射线发射、传播及接收点场强计算等步骤,为无线网络规划提供重要依据。
|
3天前
|
传感器 算法 物联网
基于粒子群算法的网络最优节点部署优化matlab仿真
本项目基于粒子群优化(PSO)算法,实现WSN网络节点的最优部署,以最大化节点覆盖范围。使用MATLAB2022A进行开发与测试,展示了优化后的节点分布及其覆盖范围。核心代码通过定义目标函数和约束条件,利用PSO算法迭代搜索最佳节点位置,并绘制优化结果图。PSO算法灵感源于鸟群觅食行为,适用于连续和离散空间的优化问题,在通信网络、物联网等领域有广泛应用。该算法通过模拟粒子群体智慧,高效逼近最优解,提升网络性能。

热门文章

最新文章