您好,欢迎来到华佗养生网。
搜索
您的当前位置:首页动态规划算法_斐波那契数列模型

动态规划算法_斐波那契数列模型

来源:华佗养生网

一、第N个泰波那契数

泰波那契序列 Tn 定义如下: 

T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2

给你整数 n,请返回第 n 个泰波那契数 Tn 的值。

对于一道动态规划类型的算法题,通常由以下几个步骤解题

算法原理

1.状态表示:创建一个dp表,用来存储所求得的数据。即dp[i]:第i个泰波那契数

2.状态转移方程:由题目给出的递推关系可以得出如下信息:

第N个数据是第N-1,N-2,N-3个数据的和,即dp[i]=dp[i-1]+dp[i-2]+dp[i-3];

3.dp表的初始化,要保证填表的时候,数据不会发生越界访问

由题意可得,dp[0] = 0,dp[1]=1,dp[2]=2;

4.填表顺序,保证填写当前状态的时候,所需要的状态已经计算出来

由状态转移方程可以知道本题的填表顺序是从左向右

5.返回值 由题目要求和状 态表示两部分可以推断出 本题的返回值是dp[n];

判断N是否会发生越界访问

编写代码

复杂度分析:上述解创建一个大小为N顺序表,故空间复杂度为O(N)

使用一次循环,时间复杂度是O(N)

下面介绍另外一种空间优化策略

通过分析上述解法我们可以发现,对于创建的dp表,每次只需用到四个数据的空间,所以可以选择滚动数组来优化空间;但是要注意迭代的顺序,具体可以参考下面的代码。

空间优化过的时间复杂度仍然是O(N),但是空间复杂度是O(1)。

二、三步问题

三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模1000000007。

题意解析

1.状态表示:创建一个dp顺序表,dp[i]表示:到达i位置是共有多少种方法

2.状态转移方程: 以i位置最近的一步来划分问题,对于dp[i],可以 从i-1级台阶跳一步上来,也可以从i-2ji级台阶跳两步上来,也可以从i-3级台阶跳三步上来。故有:

dp[i] = dp[i-1] + dp[i-2] + dp[i-3],即到第i级台阶的方法是到 i-1,i-2, i-3级台阶的方法总和。

注意求解过程中可能会发生越界访问,要对求的数据进行取模

3.初始化,为了防止发生越界访问,要注意初始化的方法,通过以上分析可以发现,要对前三级台阶进行初始化,即:

dp[1] = 1, dp[2] = 2, dp[3] = 3

4.填表顺序,要保证填写当前状态时,所需要的状态已经计算过,此题的填表顺序是从左向右

5.返回值:通过以上分析我们可以知道此题的返回值是dp[n]

代码如下

时间复杂度是O(N),空间复杂度O(N)。

三、最小花费爬楼梯

给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。请你计算并返回达到楼梯顶部的最低花费。

题意解析

由题意可以得出一条隐含信息:对于大小为n的cost数组,cost[0]到cost[n-1]表示台阶花费,cost[n-1]的下一个位置才表示楼顶。

对于一个cost = [1,100,1,1,1,100,1,1,100,1]的数组,将从下标为 0 的台阶开始。

- 支付 1 ,向上爬两个台阶,到达下标为 2 的台阶。
- 支付 1 ,向上爬两个台阶,到达下标为 4 的台阶。
- 支付 1 ,向上爬两个台阶,到达下标为 6 的台阶。
- 支付 1 ,向上爬一个台阶,到达下标为 7 的台阶。
- 支付 1 ,向上爬两个台阶,到达下标为 9 的台阶。
- 支付 1 ,向上爬一个台阶,到达楼梯顶部。
总花费为 6 。

算法原理

 解法一:以dp[i]为终点计算

1.状态表示:dp[i]表示到达i位置时的最小花费

2.状态转移方程:对与到达i位置的台阶有两种方法

第一种是从i-1的位置花费cost[i-1]向上爬一级台阶,到达i位置,花费dp[i-1]+cost[i-1]。

第二种是从i-2的位置花费cost[i-2]向上爬两级台阶,到达i位置,花费dp[i-2]+cost[i-2]。

因为do[i]要最小花费,故dp[i] = min(dp[i-1]+cost[i-1],dp[i-1]+cost[i-2])。取两者的最小值。

3.初始化,保证填表时不会发生越界访问

由状态转移方程可以知道需要初始化的数据是dp[0]和dp[1],即dp[0] = dp[1] = 0

4.填表顺序,保证在计算i位置的状态时,所需要的其他位置的状态已经计算出来。

由状态转移方程可以知道,计算i位置时,需要使用到  i - 1 和 i - 2 的位置的数据,故此题的填表顺序是从左到右。

5.返回值,由题意知道此题要求的是到达楼顶的最下花费,故返回值是dp[n]

代码如下

解法二:以dp[i]为起点计算

1.状态表示    dp[i]表示从i位置出发,到达楼顶的最小花费。

2.状态转移方程    因为每次只能向上爬一级或者两级台阶,所以dp[i]有两种情况

第一种:支付cost[i],向上爬一级台阶,从i+1位置到达终点,  dp[i+1]+cost[i]

第二种:支付cost[i],向上爬两级台阶,从i+2位置到达终点,     dp[i+2]+cost[i]

所以有 dp[i] = min(dp[i+1], dp[i+2]) + cost[i];

3.初始化      有状态转移方程可以知道应该初始化后面的值,dp数组与cost数组同等规模即可

dp[n-1] = cost[n-1]   dp [n-2] = cost[n -2].

4.填表顺序:有上述的状态转移方程可以知道,应该从右向左填表

5.返回值   应该返回dp[0] 和 dp[1]两者的最小值,即min(dp[0],dp[1])


时间复杂度是O(N),空间复杂度是O(N)。

 四、解码方法

 题目解析

对于字符串s = "226",它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) ,共有三种解码方法。

算法原理

1.状态表示   dp[i]表示以i位置为结尾,所有的解码方法

2.状态转移方程    根据最近一步来划分问题,对与字符s[i]一共有两种解码方法

第一种   s[i]单独解码,(1)当1 <= s[i] <= 9时,解码成功,即在0 - i-1位置解码成功的所有字符后面加一个字符s[i],所以有dp[i] = dp[i-1]。(2)当解码不成功时,因为i位置是最后一个字符了,所以整个字符串解码失败,返回-1。

第二种   s[i]与s[i-1]结合解码,(1)解码成功时,10 <= s[i-1]*10+s[i-1] <=26,即在0 -- i-2位置解码成功的所有字符串后面加一个字符,故有dp[i] = dp[i-2] 。(2)当解码不成功时,因为i位置是最后一个字符了,所以整个字符串解码失败,返回-1。

综上有  dp[i] = dp[i-1] + dp[i-2],  只有解码成功时才会加。

3.初始化    保证填表时不会越界,由状态转移方程可以知道应该初始化dp[0]和dp[1]。

dp[0] = 1,解码成功时,dp[0] = 0,解码不成功

dp[1] = 1  两个位置解码成一个字符,dp[1] = 2,两个位置分别单独解码成两个字符,

否则,两种情况都不存在时,dp[1] = 0。

4.填表顺序   由状态转移方程可以知道填表顺序应该是从左往右。

5.返回值  因为要解码到字符串的最后一个位置s[n-1],所以要返回dp[n-1]。

编写代码

时间复杂度和空间复杂度都为O(N)。

优化处理    将初始化操作放在填表过程中,多开一个位置的空间,将整个数组统一往后移一个位置处理边界问题以及初始化操作

原始数组下标         s   [ 0, 1, 2, 3, 4 ,......n-1]

旧dp表的下标         dp [0, 1, 2, 3, 4 ,......n-1],    将每个位置依次向后移动一位得到新dp表

新dp表的下标         dp [0, 1, 2, 3, 4 ,......n-1,n]

注意事项

1.虚拟节点里的值要保证后面的填表是正确的

在此题中,如果s[1]与s[2]一起解码成功,由递推关系dp[i] += dp[i-2];  有dp[2] += dp[0]; 所以 dp[0] 应该初始化为1。

2.原始字符串与新dp表的下标映射关系

优化后的代码

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- huatuo7.cn 版权所有 湘ICP备2022005869号-9

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务