动态规划--斐波那契数列(剑指offer)

DP定义:

动态规划是分治思想的延伸,通俗一点来说就是大事化小,小事化无的艺术。在将大问题化解为小问题的分治过程中,保存对这些小问题已经处理好的结果,并供后面处理更大规模的问题时直接使用这些结果。

动态规划具备了以下三个特点

把原来的问题分解成了几个相似的子问题。
所有的子问题都只需要解决一次。
储存子问题的解。

动态规划的本质:

是对问题状态的定义和状态转移方程的定义(状态以及状态之间的递推关系)

动态规划问题一般从以下四个角度考虑:

状态定义
状态间的转移方程定义
状态的初始化
返回结果
状态定义的要求: 定义的状态一定要形成递推关系。
一句话概括: 三特点四要素两本质
适用场景: 最大值/最小值, 可不可行, 是不是,方案个数

举例:

斐波那契数列定义:
斐波那契数列
F(n)=F(n-1)+F(n-2)(n>=2,n∈N*),其中F(1)=1,F(2)=1
输入描述:
一个正整数n
返回值描述:
输出一个正整数。
方法1:
递归实现

class Solution{
public:
int Fibonacci(int n){
   // 初始值
    if (n <= 0){
      return 0;
    }
   if (n == 1 || n == 2) {
     return 1;
   }
   // F(n)=F(n-1)+F(n-2)
   return Fibonacci(n - 2) + Fibonacci(n - 1);
  }
};
/*
递归的方法时间复杂度为O(2^n),随着n的增大呈现指数增长,效率低下
当输入比较大时,可能导致栈溢出
在递归过程中有大量的重复计算
*/  

方法2:
动态规划

/*
方法二:动态规划
状态:F(n)
状态递推:F(n)=F(n-1)+F(n-2)
初始值:F(1)=F(2)=1
返回结果:F(N)
*/
class Solution2{
public:
    int Fibonacci(int n){
    // 初始值
    if (n <= 0){
         return 0;
     }
    if (n == 1 || n == 2) {
         return 1;
     }
     // 申请一个数组,保存子问题的解,题目要求从第0项开始
     int* record = new int[n + 1];
     record[0] = 0;
     record[1] = 1;
     for (int i = 2; i <= n; i++){
        // F(n)=F(n-1)+F(n-2)
        record[i] = record[i - 1] + record[i - 2];
     }
      return record[n];
      delete[] record;
  }
};
class Solution {
public:
    int Fibonacci(int n) {  
    /*
    上述解法的空间复杂度为O(n)
    其实F(n)只与它相邻的前两项有关,所以没有必要保存所有子问题的解
    只需要保存两个子问题的解就可以
    下面方法的空间复杂度将为O(1)
*/
        //f(n-2)
        int fn2=0;
        //f(n-1)
        int fn1=1;
        int fn;
        if(n<=1)
            return n;
        for(int i=2;i<=n;++i)
        {
            fn=fn1+fn2;
            fn2=fn1;
            fn1=fn;
        }
        return fn;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值