万字详解递归与递推

news2025/6/27 12:42:14

秋名山码民的主页
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
🙏作者水平有限,如发现错误,还请私信或者评论区留言!

👍目录

  • 前言
  • 递归
    • 斐波那契数列问题的递归
      • 爬楼梯问题力扣
    • 递归实现排列型枚举
    • 递归实现组合型枚举
  • 递推
    • 递推的斐波那契
    • 带分数
    • 翻硬币
  • 最后


前言

相信这个故事,朋友们应该都不陌生,

从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?「从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?『从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?……』」

递归指由一种(或多种)简单的基本情况定义的一类对象或方法,并规定其他所有情况都能被还原为其基本情况。上面的故事就是一个简单的递归,当然还有斐波那契数列等等,一系列我们熟知的。

递归

递归是将原问题拆成多个子问题然后求解,递归的代码往往很短,可能进行重复求解某些问题,而动态规划是在递归的基础上保存了子问题的解,避免重复计算。下面我们通过例题来加深对递归的理解

斐波那契数列问题的递归

爬楼梯问题力扣

题目描述: 有 N 阶楼梯,每次可以上一阶或者两阶,求有多少种上楼梯的方法。

定义一个数组 dp 存储上楼梯的方法数(为了方便讨论,数组下标从 1 开始),dp[i] 表示走到第 i 个楼梯的方法数目。第 i 个楼梯可以从第 i-1 和 i-2 个楼梯再走一步到达,走到第 i 个楼梯的方法数为走到第 i-1 和第 i-2 个楼梯的方法数之和。

在这里插入图片描述

思路一:直接递归

class Solution {
    public int climbStairs(int n) {
        if(n == 1)
            return 1;
        if(n == 2)
            return 2;
        return climbStairs(n-1) + climbStairs(n-2);
    }
}

在这里插入图片描述
发现超时了,原因是我们对于climbStairs递归进行了重复的计算,dp的方程不难看出:
在这里插入图片描述

思路二:动态规划

class Solution {
    public int climbStairs(int n) {
        int[] dp = new int[n + 1];
        dp[0] = 1;
        dp[1] = 1;
        for(int i = 2; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
}

递归实现排列型枚举

题目描述:把 1∼n 这 n个整数排成一行后随机打乱顺序,输出所有可能的次序。
输入格式:一个整数 n。
输出格式:按照从小到大的顺序输出所有方案,每行 1 个。首先,同一行相邻两个数用一个空格隔开。其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面。
数据范围:1≤n≤9

输入样例:3
输出样例:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

思路:数据范围是1~9,推断可能选择的算法为,暴力递归,指数级别,dfs+剪枝
排列型枚举,依次枚举每个数放到哪个位置,从小到大枚举,肯定是字典序最小,转换为递归搜索树为:

在这里插入图片描述

import java.util.Scanner;

/**
 * @Author 秋名山码神
 * @Date 2023/1/30
 * @Description
 */
public class 排列枚举每个数 {
    static int N = 10;
    static int n;
    static int[] state = new int[N];//0表示没放数,1~n表示放了哪个数
    static boolean[] used = new boolean[N];

    public static void dfs(int u){
        if(u>n){
            for(int i = 1; i<=n; i++){
                System.out.print(state[i]);
            }
            System.out.println();
            return;
        }

        //依次枚举每个分支
        for(int i = 1; i<=n; i++){
            if(!used[i]){
                state[u] = i;
                used[i] = true;
                dfs(u+1);

                //恢复现场
                state[u] = 0;
                used[i] = false;
            }
        }
    }
    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        n = cin.nextInt();
        dfs(1);//从1开始,最后打印除了就是字典序最小
    }
}

递归实现组合型枚举

题目描述:
从 1~n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案。

输入格式:
两个整数 n,m ,在同一行用空格隔开。

输出格式:
按照从小到大的顺序输出所有方案,每行1个。
首先,同一行内的数升序排列,相邻两个数用一个空格隔开。
其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如1 3 5 7排在1 3 6 8前面)。

数据范围:n>0,0≤m≤n ,n+(n−m)≤25

输入样例:
5 3
输出样例:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5

思路:加粗样式

import java.util.Scanner;

/**
 * @Author 秋名山码神
 * @Date 2023/1/30
 * @Description
 */
public class 组合枚举每个数 {
    static int N = 30;
    static int n,m;
    static  int[] ways = new int[N];

    public static void dfs(int u,int start){
        //剪枝, 如果把后面的数都选上还不够m,意味这无解,例如4开始,……
        if(u+n - start <m) return;
        if(u == m +1){
            for(int i = 1; i<=m; i++){
                System.out.print(ways[i] + " ");
            }
            System.out.println();
        }

        for(int i = start; i<=n; i++){
            ways[u] = i;
            dfs(u+1,i+1);

            ways[u] = 0;//实际上是没有意义的,恢复现场,前面给覆盖掉了
        }
    }
    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        n = cin.nextInt();
        m = cin.nextInt();
        dfs(1,1);
    }
}

递推

前面的递归我们是从原问题来推出子问题,递推刚好相反,递推:子问题推出原问题

递推的斐波那契

题目描述:
输入一个整数N,输出这个序列的前N项。(序列为斐波那契数列)

数据范围:0<N<46

import java.util.Scanner;

/**
 * @Author 秋名山码神
 * @Date 2023/1/31
 * @Description
 */
public class fib {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();

        int[] f = new int[46];
        f[1] = 0;
        f[2] = 1;
        for(int i = 3; i<= n; i++){
            f[i] = f[i-1] + f[i-2];
        }
        for(int i = 1; i<=n; i++)
            System.out.print(f[i]+" ");
        System.out.println();
    }
}

带分数

来源:第四届蓝桥杯省赛C++B/C组,第四届蓝桥杯省赛JAVAA/B组

在这里插入图片描述
数据范围:1 <= N < 10^6

目标是找到三个数,使得n=a+b/c,可以考虑使用暴力解法将1~9的全排列给一个个搜出来,然后每次找到一种排列,就利用二重循环将该段排列分成三段,第一段得到a,第二段得到b,第三段得到c,然后进行判断即可

优化: n是已知的,可以把等式变形为,cn = c *a + b,枚举ac,直接算出b

package 递归;

import java.util.Scanner;

/**
 * @Author 秋名山码神
 * @Date 2023/1/31
 * @Description
 */
public class 带分数真题 {
    static boolean[] st = new boolean[12];
    static int[] ans = new int[12];
    static int n = 100;
    static int res = 0;
    public static void dfs(int x)
    {
        if(x > 9)
        {

            for(int i = 1;i <= 7;i++)
                for(int j = i + 1;j <= 8;j++)
                {
                    int a = 0;
                    int b = 0;
                    int c = 0;
                    int cnt = 1;
                    for(int k = 1;k <= i;k++)
                    {
                        a += ans[k] * cnt;
                        cnt *= 10;
                    }
                    cnt = 1;
                    for(int k = i + 1;k <= j;k++)
                    {
                        b += ans[k] * cnt;
                        cnt *= 10;
                    }
                    cnt = 1;
                    for(int k = j + 1;k <= 9;k++)
                    {
                        c += ans[k] * cnt;
                        cnt *= 10;
                    }
                    if(b % c == 0)
                    {
                        if(a + b/c == n) {res ++;}
                    }
                }

            return;
        }
        for(int i = 1;i <= 9;i++)
        {
            if(st[i]) continue;
            ans[x] = i;
            st[i] = true;
            dfs(x + 1);
            st[i] = false;
        }

    }
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        dfs(1);
        System.out.println(res);
    }
}

翻硬币

来源:第四届蓝桥杯省赛C++B组
在这里插入图片描述
数据范围:n<100

暴力递归可以写


import java.util.Scanner;

/**
 * @Author 秋名山码神
 * @Date 2023/1/31
 * @Description
 */
public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String ss1 = sc.next();
        String ss2 = sc.next();
        char[] s1 = ss1.toCharArray();
        char[] s2 = ss2.toCharArray();
        int cnt = 0;
        for(int i = 0; i < s1.length-1; i++){
            if(s1[i] != s2[i]){
                cnt++;
                if(s1[i] == '*')
                    s1[i] = 'o';
                else
                    s1[i] = '*';

                if(s1[i+1] == '*')
                    s1[i+1] = 'o';
                else
                    s1[i+1] = '*';
            }
        }
        System.out.println(cnt);
    }
}

最后

看在博主这么努力,熬夜肝的情况下,给个免费的三连吧!
请添加图片描述

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

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

相关文章

js 点击图片实现查看大图

js 点击图片实现查看大图 点击图片放大缩小&#xff08;遮罩&#xff09; 截图&#xff1a;点击放大&#xff0c;并显示ico放大镜 代码如下&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>点击图片放大缩…

buu 浪里淘沙 1

题目描述&#xff1a; 题目分析&#xff1a; 看了这一大串字符串&#xff0c;发现里面都是由16个字母组成&#xff0c;即 “tonight success notice we example crypto should back space sublim found system morning user the enter ”&#xff0c;并且这16个字母在第一行中…

【Kotlin】DSL 领域特定语言 ① ( apply 标准库函数分析 | 普通匿名函数 | 扩展匿名函数 | 泛型扩展匿名函数 )

文章目录一、apply 标准库函数分析1、apply 函数展示2、apply 函数原型分析函数原型参数和返回值分析3、匿名函数类型分析4、扩展函数回顾5、泛型扩展函数函数类型6、泛型扩展匿名函数7、apply 标准库函数参数分析泛型扩展函数匿名函数 与 普通匿名函数 对比apply 函数参数不是…

登高望远,一文解答 2023 年你最关心的前端热点问题

动手点关注干货不迷路本文预计阅读 25 min&#xff0c;建议先收藏后观看~一、刀光剑影的 2022时光荏苒&#xff0c;这绝不平淡的 2022 年已经走上历史的黄页&#xff0c;新的一年也逐渐看不到故人回首的光影。感谢你对前端技术领域持续关注&#xff0c;我们一直在这里等你。① …

致敬2202年,这些优秀的裁缝们

文 | 鹰钩鼻涕虫2202年过去了&#xff0c;不知道小伙伴们是否和我一样&#xff0c;绝大多数时间处于迷茫之中&#xff0c;除去其他因素不谈&#xff0c;在最后一个月到来之前&#xff0c;NLP 学界的表现似乎不如前几年那样“精彩”&#xff0c;甚至可说是“寡淡”&#xff0c;翻…

spring事务执行流程分析_5(注解形式 advisor等前置对象的生成)

调用beanFactory处理器 依旧进入刷新refresh方法AbstractApplicationContext#refresh -> 在上一篇文章spring事务执行流程分析_4(注解形式 EnableTransactionManagement的作用) 解析EnableTransactionManagement注解就是在此方法进行的,也就是在会注册 名字&#xff1a;i…

简单模拟vue实现数据劫持-视图更新双向绑定-2

接上&#xff0c; new一个实例对象&#xff0c;vc&#xff0c;构造函数动态绑定一个空对象&#xff0c;并在构造函数上绑定静态方法 $on进行事件的注册&#xff0c;$emit抛出执行事件 function observe() {// 利用策略模式-可以快速根据特定的事件&#xff0c;执行多个函数th…

最全总结 | 聊聊 Selenium 隐藏浏览器指纹特征的几种方式!

大家好&#xff0c;我是安果&#xff01;我们使用 Selenium 对网页进行爬虫时&#xff0c;如果不做任何处理直接进行爬取&#xff0c;会导致很多特征是暴露的对一些做了反爬的网站&#xff0c;做了特征检测&#xff0c;用来阻止一些恶意爬虫本篇文章将介绍几种常用的隐藏浏览器…

第九层(9):STL之map/multimap

文章目录前情回顾map/multimap概念差别构造函数赋值操作大小操作函数交换函数插入函数删除函数查找函数统计函数排序规则下一座石碑&#x1f389;welcome&#x1f389; ✒️博主介绍&#xff1a;一名大一的智能制造专业学生&#xff0c;在学习C/C的路上会越走越远&#xff0c;后…

三线金叉选股公式,均线、成交量、MACD共振

均线、成交量、MACD三线金叉共振选股公式思路还是比较简单的&#xff0c;分别写出均线金叉、成交量的均量线金叉、MACD的快线和慢线金叉&#xff0c;最后用AND连接这三个条件。 一、编写选股公式所需通达信函数 1、EXIST函数 含义&#xff1a;是否存在 用法&#xff1a;EXIST…

OpenGL | 搭建OpenGL 画画框架

一、搭建OpenGL 画画框架3D场景初始化&#xff08;1&#xff09; 代码void Init() {glMatrixMode(GL_PROJECTION); //将当前矩阵指定为投影矩阵,对投影矩阵操作gluPerspective(50.0f, 800.0f / 600.0f, 0.1f, 1000.0f);//创建一个对称的透视投影矩阵&#xff0c;并且用这个…

世界上最大型的 Demo Drop DJ 比赛来到元宇宙!

简要介绍 WBDD 于 2023 年 1 月 26 日至 2 月 8 日进入元宇宙。 认识世界上最大型的 DJ 比赛获胜者&#xff0c;并在元宇宙中伴随着他们的音乐跳舞。 该体验将是线下活动的延伸&#xff0c;由 Mike Williams 担任活动大使。 体验将对所有人开放。 完成 80% 的任务&#xff…

51单片机简易出租车计费系统仿真设计( proteus仿真+程序+报告+讲解视频)

51单片机简易出租车计费系统仿真设计( proteus仿真程序报告讲解视频&#xff09; 仿真图proteus 8.9及以上 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;S0036 51单片机简易出租车计费系统仿真设计讲解视频1.主要功能&#xff1a;…

MXNet实现图片的样式风格迁移(Style Transfer)

样式迁移就是将一个样式&#xff08;风格&#xff09;应用到一张主图上&#xff0c;改变这张图片的风格&#xff0c;比如说拍摄了一张夜晚的图片&#xff0c;我们可以拿梵高的"星月夜"图片做样式&#xff0c;应用到拍摄的图片上&#xff0c;两者合成后的新图片&#…

linux基本功系列之uptime命令实战

文章目录一. uptime命令介绍二. 语法格式及常用选项三. 参考案例3.1 显示当前系统运行负载情况3.2 显示机器正常运行的时间3.3 显示机器启动时间3.4 关于平均负载的介绍总结前言&#x1f680;&#x1f680;&#x1f680; 想要学好Linux&#xff0c;命令是基本功&#xff0c;企业…

推荐 5 个实用 GitHub 项目

本期推荐开源项目目录&#xff1a;1. AI-For-Beginners2. 一个小巧轻便的 PDF 阅读器3. 开源的智能手表4. 开源内容管理系统5. 程序员海外工作/英文面试手册01AI-For-Beginners之前推荐过 Microsoft 出品的 Web 技术栈课程&#xff0c;本开源项目同样是 Microsoft 的 Azure Clo…

go runtime

go 运行时&#xff0c;也称为 go runtime&#xff0c;类似Java中的JVM虚拟机&#xff0c;不过runtime并非是虚拟机。其本身就是每个 go 程序的一部分&#xff0c;它会跟源码一起编译并链接到目标程序中&#xff0c;即便只写了一个 hello world 程序&#xff0c;这个程序中也包含…

day15 二叉树 | 104、二叉树的最大深度 111、二叉树的最小深度 222、完全二叉树的节点个数

题目 104、二叉树的最大深度 递归法&#xff08;后序&#xff09;&#xff08;必须会&#xff09; // 定义&#xff1a;输入根节点&#xff0c;返回这棵二叉树的最大深度 int maxDepth(TreeNode root) {if (root null) {return 0;}// 利用定义&#xff0c;计算左右子树的最大…

论文笔记:Graph WaveNet for Deep Spatial-Temporal Graph Modeling

IJCAI 2019 1 abstract & intro 时空数据挖掘问题大多数使用邻接矩阵来建模节点之间的属性关系&#xff0c;这种思路的一个基本假设是&#xff1a;节点信息取决于自身和邻居的历史信息。 但这类模型的假设存在着一些问题&#xff1a; 未能充分建模节点之间的依赖关…

宝塔部署springboot,vue,node.js项目

宝塔部署springboot项目&#xff1a; 先将命令转移到jar包所属文件夹中 分为短暂部署和永久部署 短暂部署&#xff1a;java -jar xxx.jar 永久部署&#xff1a;nohup java -jar demo-1.0.0.jar logs_mark.txt 2>&1 & nohup:linux的命令,代表关闭但持续运行 查看898…