【动态规划】斐波那契数列


关于斐波那契数列,相信学过函数递归的友友们肯定晓得这是啥,不过为加强动态规划的思想学习,本居开了新的专题——动态规划,在这里将会简要介绍一下动态规划的思想,用该思想来开启一种高效的斐波那契数列的求解之法,并以该例子为开头,深入探究学习动态规划。

啥是动态规划?

用人话来解释就是大事化小,小事化了分治思想

好的,这话好像在哪见过,没错,在学习函数递归的时候,用的就是该思想,但是有所不同的是,动态规划在分治的过程中,对小问题处理好的结果进行了保存,等到之后在处理更大规模问题时可以直接使用这些结果,而不是每次求大问题时都从小问题入手,吭哧吭哧求大问题。

具体思考问题的四个角度:

  1. 状态定义
  2. 状态间的转移方程定义
  3. 状态的初始化
  4. 返回结果

就拿本案例来说!

牛客链接

在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)来求第N项斐波那契数列

递归思想

如果用递归的思想来求,非常简单,应该是这样的:

public class Solution {
    
    
    public int Fibonacci(int n) {
    
    
        if(n <= 0) {
    
    
            return 0;
        }
        //边界条件
        if(n == 1 || n == 2) {
    
    
            return 1;
        }
        //按照定义总结出的递归式
        return Fibonacci(n - 1) + Fibonacci(n - 2);
    }
}

代码虽简单,但当n越大,包含的运算的量就会以指数形式爆发增长。

在这里插入图片描述

由图可见,当n的值较小的时候,计算是非常简单的,但是当n的值变大时,就会出现大量的重复计算,n为5的时候,Fib(1)就已经2次参与运算,Fib(2)就已经3次参与运算,Fib(3)被重复计算了2次,可想而知,当n越变越大时,重复计算的量就会大量增加,计算的速度会随着n的增加肉眼可见的变慢,程序甚至会挂。

因此,若是将每次计算出的小问题存起来就可以很好地提高效率,我们可以准备一个数组来存放小问题的结果!

动归思想

状态定义:Fib(i)的值即斐波那契数列的第i个值

状态间的转移方程定义:Fib(i) = Fib(i - 1) + Fib(i - 2)

状态的初始化:Fib(0) = 0 Fib(1) = 1

返回结果:返回Fib(n)的值即斐波那契数列的第n个值

public class Solution {
    
    
    public int Fibonacci(int n) {
    
    
        if(n == 1||n == 2) return 1;
        if(n <= 0) return 0;
        int[] Fib = new int[n + 1]; //用来存放每次计算出的斐波那契数
        Fib[0] = 0;
        Fib[1] = 1; //状态的初始化
        Fib[2] = 1;
        for(int i = 3;i <= n;i ++) {
    
    
            Fib[i] = Fib[i - 1] + Fib[i - 2]; //转移方程
        }
        return Fib[n]; //返回所求的第n位斐波那契数
    }
}

动归思想(改良)

根据题目所要求的,实际上我们只需要知道第n项的前两项即可,并不需要将斐波那契数列中位数比n小的全部放到数组当中,只需要在循环的过程中不断更新n - 1,n - 2为斐波那契数的值即可。

public class Solution {
    
    
    public int Fibonacci(int n) {
    
    
        if(n == 1||n == 2)return 1;
        if(n <= 0) return 0;
        int ret = 0;
        int n1 = 1; //n - 1位的初始值
        int n2 = 1; //n - 2位的初始值
        for(int i = 3;i <= n;i ++) {
    
    
            ret = n1 + n2; //转移方程
            n2 = n1;       //更新n - 2位的值
            n1 = ret;      //更新n - 1位的值
        }
        return ret;        //返回结果
    }
}

完!

猜你喜欢

转载自blog.csdn.net/weixin_46103589/article/details/121865054
今日推荐