动态规划1-斐波那契入动规

动态规划是一种有效解决子问题重叠情况的算法,通过存储子问题结果避免重复计算。文章介绍了斐波那契数列的递归和迭代解法,并探讨了跳台阶问题,其解法同样基于斐波那契数列。通过对经典问题的分析,展示了动态规划如何以空间换时间提升效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动态规划

参考题解任意门1

参考题解任意门2

分治:将问题划分成互不相交的子问题,然后递归地求解子问题,最后将子问题组合起来得到原问题解。(eg.归并排序)

动态规划:和分治类似,但应用于子问题重叠的情况,即不同的子问题具有公共的子问题(在这种情况下使用分治会重复执行很多不必要的工作)。所以动态规划只对每个子问题求一次解,将结果存在一个表格中,需要使用时直接查表即可。(DP常常使用一维或二维表格存储中间结果值)

  • 以时间换取空间效率
  • 常用于求解最优化问题

DP经典问题

斐波那契数列

又称黄金分割数列,以兔子繁殖为例引入,又称“兔子数列”。指的是这样一组数字:1,1,2,3,5,8,13,……
F ( n ) = { 1 , n = 1 , 2 F ( n − 1 ) + F ( n − 2 ) , n ≥ 3 F(n)=\begin{cases} 1,n=1,2\\ F(n-1)+F(n-2), n\geq3\end{cases} F(n)={1n=1,2F(n1)+F(n2)n3

递归写法

递归的实现方式,会执行大量重复的函数调用,时间效率很低,运行时间为指数时间。

// 给定n,求F(n)
int DP_Solution::Fibonacci(int n)
{
    if(n <= 1) return n;
    return Fibonacci(n - 1) + Fibonacci(n - 2);
}
迭代写法

对于求第n项值,需要保存第n-1和第n-2项的值,牺牲一点内存,换取多项式的运行时间。

int DP_Solution::Fibonacci2(int n)
{
    if(n <= 1) return n;
    int f1 = 0;
    int f2 = 1;
    int fn = 0;
    for(int i = 2; i <= n; i++){
        fn = f2 + f1;
        f1 = f2;
        f2 = fn;
    }
    return fn;
}
测试用例
int main()
{
    DP_Solution dp_s;
    time_t start, end;
    start = time(NULL);
    int res = dp_s.Fibonacci(40);
    end = time(NULL);
    cout << res << endl; // 102334155
    cout << "time: " << (end - start) << "s" << endl;  // 1 s
    time_t start1, end1;
    start1 = time(NULL);
    int res2 = dp_s.Fibonacci2(40);
    end1 = time(NULL);
    cout << res2 << endl; // 102334155
    cout << "time: " << (end1 - start1) << "s" << endl;  // 0 s
}

跳台阶

问题:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级台阶总共有多少种跳法?

思路:把n级台阶的跳法种数看成n的函数F(n),n=1的时候,F(n) = 1;n=2时,F(n)=2;n>2时,第一次跳有两种不同的选择,第一种是跳一级,那么F(n)就等于跳剩下的n-1级台阶种数,第二种是跳2级,那么F(n)就等于跳剩下的n-2级台阶种数,所以F(n) = F(n-1) + F(n-2)。
F ( n ) = { 1 , n = 1 2 , n = 2 F ( n − 1 ) + F ( n − 2 ) , n > 2 F(n)=\begin{cases} 1,n=1\\ 2,n=2\\ F(n-1)+F(n-2), n>2\end{cases} F(n)=1n=12n=2F(n1)+F(n2)n>2

int DP_Solution::JumpSteps(int n)
{
    if(n <= 2) return n;
    int f1 = 1;
    int f2 = 2;
    int fn = 0;
    for(int i = 3; i <= n; i++){
        fn = f1 + f2;
        f1 = f2;
        f2 = fn;
    }
    return fn;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值