题目链接
动规五部曲:1、确定dp数组的下标以及dp数组的含义:dp[i]表示第i个斐波那契数为dp[i]。
2、确定递推公式。题目中已经给出了,dp(n) = dp(n - 1) + dp(n - 2)
3、dp数组如何初始化。题目也给出了,dp(0) = 0,dp(1) = 1
4、确定遍历顺序。由递推公式可得出是从前向后遍历。当然有的题是从后向前遍历,也有可能两层for循环的先后顺序是有说法的。
5、打印dp数组。
方法一:维护一整个数组,
class Solution {
public:
int fib(int n) {
if(n<=1) return n;
vector dp(n+1);
//思考的过程应该是先想递推公式,再想初始化,因为初始化是依赖于递推公式的
dp[0]=0;dp[1]=1;
int i;
for(i=2;i<=n;i++){
dp[i]=dp[i-1]+dp[i-2];
}
//return dp[i];//这样写出错,因为跳出for循环之前i又做了一次加加,也就是等于n+1
return dp[n];
}
};
错因:1、int i写在了for循环里面,出for循环后没有定义,应该写在外面。
2、最后写成了return dp[i],但此时跳出for循环的时候i已经是n+1了。
注意dp数组的定义方式。
方法二:我们发现求dp[i],只依赖于前两个数值,所以我们没必要维护一整个数组,只需要维护三个变量即可。
class Solution {
public:
int fib(int n) {
if(n<=1) return n;//0或1都是返回自己,题目中是从0开始
int dp[2];
dp[0]=0;
dp[1]=1;
for(int i=2;i<=n;i++){
int sum=dp[0]+dp[1];
dp[0]=dp[1];
dp[1]=sum;
}
return dp[1];
}
};
错因:同样的,返回sum会报未定义的错。
方法三:本题也可以用递归的思路来解。
class Solution {
public:
int fib(int n) {
if(n<2) return n;
return fib(n-1)+fib(n-2);
}
};
题目链接
本题的难点在于确定递推公式,确定之后发现和斐波那契数列相同。
1、明确dp数组的下标及数组的含义。dp[i]是到达第i阶有dp[i]种方法。
2、确定递推公式。
3、明确dp数组如何初始化。n是大于0的,dp[0]没有含义。
4、确定遍历顺序。从前向后。
5、打印dp数组。(出问题后打印出来)
class Solution {
public:
int climbStairs(int n) {
if(n<2) return n;
vector dp(n+1);
dp[1]=1;
dp[2]=2;
for(int i=3;i<=n;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
};
只需要维护三个变量即可,优化空间复杂度为O(1)。
class Solution {
public:
int climbStairs(int n) {
if(n<2) return n;
int dp[3];//只需要维护三个变量即可,注意这里是dp[3]不是dp[2]
dp[1]=1;
dp[2]=2;
for(int i=3;i<=n;i++){
int sum=dp[1]+dp[2];
dp[1]=dp[2];
dp[2]=sum;
}
return dp[2];
}
};
本题用递归会超时,本题的序列和斐波那契数列略有不同,本题是1、2。。,斐波那契数列是1、1、2。。。
题目链接
1、确定dp数组的下标以及数组含义:dp[i]是到达i位置的最小花费。
2、确定递推公式。dp[i]=min([dp[i-1]+cost[i-1],dp[i-2]+cost[i-2])。
3、确定dp数组初始化。dp[0]=0,dp[1]=0。
4、确定遍历顺序。从前向后遍历。
5、打印dp数组。
class Solution {
public:
int minCostClimbingStairs(vector& cost) {
vector dp(cost.size()+1);//楼梯还要多一层
dp[0]=0;
dp[1]=0;
for(int i=2;i