目录

  • 前言
  • 问题介绍
  • 解决方案
  • 代码编写
    • java语言版本
    • c语言版本
    • c++语言版本
  • 思考感悟
  • 写在最后

前言

当前所有算法都使用测试用例运行过,但是不保证100%的测试用例,如果存在问题务必联系批评指正~

在此感谢左大神让我对算法有了新的感悟认识!

问题介绍

原问题
有一个楼梯一共num阶,从底层往上层一次只能走1步或者2步,求登上num阶的楼梯一共有几种方式?
如:2阶楼梯,可以一次走2阶也可以走两次1阶,一共有两种方式
进阶问题
有一个农场和一只成熟的母牛,成熟的母牛一年会生一只小母牛,小母牛3年后会成为成熟的母牛并在当年开始产小母牛,问:第num年时,农场一共有多少只母牛?

解决方案

原问题
方法一:暴力递归
将问题下发到num-1阶和num-2阶即可,num阶的种数=num-1阶的种数+num-2阶的种数
时间:O(2^n)
方法二:动态规划
从第一阶和第二阶开始将到达每一阶的答案都存到数组中,直到计算到num阶为止,arr[num] = arr[num-1] + arr[num-2]
时间:O(n)
方法三:递推动态矩阵法(最优解)
首先将计算num阶和前面的状态关联起来,找到关联关系,也就是:f(num) = f(num-1) + f(num-2)
因此可以建立一个矩阵表达式:
[f(num), f(num-1)] = [f(num-1), f(num-2)] [ 1 1 1 0 ] \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} [11​10​]
通过该表达式可以推出
[f(num), f(num-1)] = [f(2), f(1)] [ 1 1 1 0 ] \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} [11​10​]^(num-2)
因此需要准备一个矩阵相乘和矩阵n次方的公共方法,剩下的工作就比较简单了~详情看代码
时间:O(logn)
进阶问题
方法一:暴力递归
每一年的母牛数等于去年的总牛数加上三年前的总牛数1 , 递归方法很简单
方法二:动态规划
通过递归可以知道动态规划如何解决,非常简单,一维动态规划即可
方法三:递推动态矩阵法(最优解)
首先将计算num阶和前面的状态关联起来,找到关联关系,也就是:f(num) = f(num-1) + f(num-3)
因此可以建立一个矩阵表达式:
[f(num), f(num-1), f(num-2)] = [f(num-1), f(num-2), f(num-3)] [ 1 1 0 0 0 1 1 0 0 ] \begin{bmatrix} 1 & 1 &0 \\ 0 & 0 & 1 \\ 1& 0 & 0 \end{bmatrix} ⎣ ⎡​101​100​010​⎦ ⎤​
通过该表达式可以推出
[f(num), f(num-1)] = [f(2), f(1)] [ 1 1 0 0 0 1 1 0 0 ] \begin{bmatrix} 1 & 1 &0 \\ 0 & 0 & 1 \\ 1& 0 & 0 \end{bmatrix} ⎣ ⎡​101​100​010​⎦ ⎤​^(num-3)

代码编写

java语言版本

矩阵相乘和矩阵n次方代码:

    /*** arr的n次方* @param arr* @param n* @return*/public static int[][] powMartrix(int[][] arr, int n) {if (arr == null || arr.length == 0 || arr[0].length == 0 ) {return arr;}int[][] res = new int[arr.length][arr[0].length];// 单位举证for (int i = 0; i < res.length; i++) {res[i][i] = 1;}for (int i = 0; i < n; i++) {res = multiMartrix(res, arr);}return res;}/*** arr的n次方* 优化版本* @param arr* @param n* @return*/public static int[][] powMartrixPro(int[][] arr, int n) {if (arr == null || arr.length == 0 || arr[0].length == 0 ) {return arr;}int[][] res = new int[arr.length][arr[0].length];// 单位举证for (int i = 0; i < res.length; i++) {res[i][i] = 1;}int[][] tem = arr;for (; n > 0; n >>= 1) {if ((n & 1) != 0){// 这波res需要乘res = multiMartrix(res, tem);}// 准备下一波的乘数,虽然可能不乘tem = multiMartrix(tem, tem);}return res;}/*** 矩阵相乘* @param arr1* @param arr2* @return*/public static int[][] multiMartrix(int[][] arr1, int[][] arr2) {if (arr1 == null || arr1.length == 0 || arr1[0].length == 0|| arr2 == null || arr2.length == 0 || arr2[0].length == 0) {return null;}// 相乘结果:行 = arr1的行 列 = arr2的列数int[][] res = new int[arr1.length][arr2[0].length];// 一行一行来for (int i = 0; i < arr1.length; i++) {for (int j = 0; j < arr2[0].length; j++){int sum = 0;for (int k = 0; k < arr1[0].length; k++) {// 这里的k是arr1的列,arr2 的行sum += arr1[i][k]*arr2[k][j];}res[i][j] = sum;}}return res;}

原问题:

    /*** 阶梯问题:递归解法* O(2^n)* @param num*/public static int process1(int num){if (num == 1) {return 1;}else if (num == 2){return 2;}else if (num == 0){return 0;}else {return process1(num-1) + process1(num - 2);}}/*** 阶梯问题:dp解法* 比递归快非常多* O(n)* @param num*/public static int dp1(int num){int[] dp = new int[num+1];dp[0] = 0;dp[1] = 1;dp[2] = 2;for (int i = 3; i <= num; i++) {dp[i] = dp[i-1] + dp[i-2];}return dp[num];}/*** logn解法* 状态矩阵相乘* @param num* @return*/public static int superFunc1(int num) {// 构造一个初始矩阵[func(2), func(1)]int[][] arr = {{2, 1}};arr =  multiMartrix(arr, powMartrixPro(new int[][]{{1,1},{1,0}},num - 2));return arr[0][0];}

进阶问题,(递归和动态规划过于简单,略):

    /*** 母牛问题* 求第years年时有多少牛* @param years* @return*/public static int cowPro(int years) {if (years <= 3){return years;}int[][] arr = {{3,2,1}};arr = multiMartrix(arr, powMartrixPro(new int[][]{{1,1,0},{0,0,1},{1,0,0}}, years-3));return arr[0][0];}

c语言版本

正在学习中

c++语言版本

正在学习中

思考感悟

这道题是一道典型的递推系列问题,目前感觉基本上很多递归算法都是递推问题,比如典型的二叉树遍历问题,根节点的各种属性依赖于左边和右边子树的属性。
所以以后遇到这种求某个状态时的个数、种数类型问题,可以考虑是否和前面的状态存在依赖关系,如果存在依赖关系就可以使用递推公式解决此类问题。同样,后面的递归和动态规划类型问题都可以使用类似的递推思想解决,这又是一个万能的思路一定要掌握!

对了还有个重要的思想:
矩阵的n次方优化,正常思考任何数或者什么东西的n次方都是累乘法,但是这里有一个非常巨大的优化就是将次方的指数2进制化,比如10的75次方,75可以分解为1001011,也就是64+8+2+1,同时10^75等于10^64 *10 ^8 * 10^2 *10 ^1, 这里可以发现,8是2的三次方,所以10的8次方不需要1次方乘8次,只需要2次方乘3次,同理,64次方可以是8次方的平方,这里的性能提升是非常巨大的,也是logn时间复杂度的精髓!
奇思妙想一下,分解成3进制、10进制为什么不行,非要2进制?
75本身就是10进制,那么75可以分解为70+5, 同时 也就是 10的70次方 * 10的5次方
到这里就可以发现指数之间是没有次方的直接关系的,但是2进制的每一位之间都是存在次方关系的(满2进1的特性,每一位只有两种状态),到这里是可以感受到计算机使用2进制的伟大之处了吧!

写在最后

方案和代码仅提供学习和思考使用,切勿随意滥用!如有错误和不合理的地方,务必批评指正~
如果需要git源码可邮件给2260755767@qq.com
再次感谢左大神对我算法的指点迷津!


  1. 这里为什么说是三年前的总牛数呢?因为三年前的总牛数就是三年后的总生产力,三年前的所有牛,三年后都是成熟的,这三年期间新增的牛都不是成熟的,所以三年后,新增的数量=三年前的总牛数! ↩︎

【算法】【递归与动态规划模块】斐波那契数列的系列问题解法及递推类型问题的最优解相关推荐

  1. C#递归、动态规划计算斐波那契数列

    //递归public static long recurFib(int num){if (num < 2){return num;}else{return recurFib(num - 1) + ...

  2. 笔试题:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。该题有三种解法:递归的方法求解斐波那契数列、用概率与统计的数学方法解决,3.动态规划

    笔试题 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶.求该青蛙跳上一个 n 级的台阶总共有多少种跳法.该题有三种解法:1.递归的方法求解斐波那契数列.2.用概率与统计的数学方法解决,3.动态规划 ...

  3. C语言数据结构----递归的应用(斐波拉契数列、汉诺塔、strlen的递归算法)

    本节主要说了递归的设计和算法实现,以及递归的基本例程斐波拉契数列.strlen的递归解法.汉诺塔和全排列递归算法. 一.递归的设计和实现 1.递归从实质上是一种数学的解决问题的思维,是一种分而治之的思 ...

  4. c语言 兔子数列螺线图,经典算法大全51例——2.斐波那契数列(兔子数列)

    经典算法大全51例--2.斐波那契数列 算法目录合集 地址 说明 题目 原理分析 代码实现--Java 相关题目其他变形: 1.爬楼梯(来源:力扣LeetCode) 2.兔子成熟期拉长 官方题解 分析 ...

  5. [python]练习之递归和循环实现斐波拉契数列

    1 # 程序功能:用递归和循环实现斐波拉契数列 2 # 0 1 1 2 3 5 8 13 21 34 3 4 def digui_fibo(number): 5 if number == 1: 6 r ...

  6. 用php递归求fibonacci数列,C++_C语言求Fibonacci斐波那契数列通项问题的解法总结,一:递归实现使用 - phpStudy...

    C语言求Fibonacci斐波那契数列通项问题的解法总结 一:递归实现  使用公式f[n]=f[n-1]+f[n-2],依次递归计算,递归结束条件是f[1]=1,f[2]=1. 二:数组实现  空间复 ...

  7. 递归经典应用之斐波那契数列

    递归经典应用之斐波那契数列 (一)递归概念 将复杂问题 递推分解为最简问题 然后将结果回归的过程 Windows - Linux Linux = Linux is not Unix 使用方法: 自己调 ...

  8. 斐波那契数列 python 高阶解法

    斐波那契数列 python 高阶解法 2022.09.27 斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以 ...

  9. 数据结构与算法--再谈递归与循环(斐波那契数列)

    再谈递归与循环 在某些算法中,可能需要重复计算相同的问题,通常我们可以选择用递归或者循环两种方法.递归是一个函数内部的调用这个函数自身.循环则是通过设置计算的初始值以及终止条件,在一个范围内重复运算. ...

最新文章

  1. Android实现手机手电筒
  2. ANDROID L——Material Design综合应用(Demo)
  3. 《IBM-PC汇编语言程序设计》(第2版)【沈美明 温冬婵】——自编解析与答案
  4. 默认登录_常见品牌路由器默认登录密码大全
  5. 微型计算机物理地址转换,微型计算机及接口技术2015年4月真题试题(04732)
  6. 【JZOJ4964】【GDKOI2017模拟1.21】Rhyme
  7. python怎么输入两个数然后求差值_python两个日期之间天差值获取
  8. java怎么快速创建监听类_如何创建监听器
  9. 107 岁的 IBM 以 340 亿美元吞下了 25 岁的“小”红帽!
  10. 漫游书海-我的阅读简史
  11. html网页模板如何修改,如何修改和管理网站模板
  12. MySql常用命令集
  13. C语言贪心算法——找钱
  14. cesium加载地形
  15. meta标签http-equiv属性实现自动刷新页面和重定向
  16. 电子签名屏什么牌子好
  17. 2021GMV目标10000亿,“好学生”抖音认真做电商
  18. 乐山计算机学校老师最受欢迎,乐山市计算机学校优秀教师白杉杉
  19. 刷爆全网的动态条形图,原来5行Python代码就能实现!
  20. linux下运行win10效果好不好,Win10不好用?继续坚守Win7的人依然巨多

热门文章

  1. 新媒体层出不穷,企业如何做好网络营销?
  2. 阿里巴巴设计公开课《数据可视化设计在行业中的实践与应用》-阿里云数字可视化大屏经验分享
  3. Unity游戏对象与图形基础
  4. 绍兴市人力资源和社会保障局异地数据容灾系统
  5. Web Service (二) WSDL详解
  6. QQ浏览器使用axios上传文件为空的问题
  7. Unity WebGL打包网页端运行显示Not allowed to access uv4 on mesh
  8. 安装Ubuntu系统教程(图文结合-详细步骤)
  9. postgres之窗口函数
  10. c++ float精度丢失