509. 斐波那契数
1. 思路
(1)确定dp数组以及下标的含义
dp数组就是斐波那契数列,下标为数列元素index
(2)确定递推公式
根据定义,dp[i] = dp[i - 1] + dp[i - 2]
(3)dp数组初始化
dp[0] = 0, dp[1] = 1
(4)确定遍历顺序
数列应该从左到右遍历
(5)举例推导dp数组
class Solution {
public:
int fib(int N) {
if (N <= 1) return N;
vector<int> dp(N + 1);
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= N; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[N];
}
};
70. 爬楼梯
1. 思路
(1)确定dp数组以及下标的含义
dp数组是到每层楼的所有可能路线,下标是楼层
(2)确定递推公式
dp[i] = dp[i-1] + dp[i-2]
状态转移,也就是说不存在跨越状态的情况,比如dp[i-3],它下一步只能到dp[i-1]和dp[i-2],因此不能直接指向dp[i]
(3)dp数组初始化
dp[0] = 0, dp[1] = 1,dp[2] = 2
(4)确定遍历顺序
应该从左到右遍历
(5)举例推导dp数组
[0,1,2]
[0,1,2,3,5...]
2. 思考
(1)这道题可以考虑dp[0]是什么,它需要定义。而在这道题里面明显没有定义,因此都可以。
(2)如果一次最多走m步,应该如何。
这需要对状态转移充分理解,这道题里面是一步状态转移,因此m步需要涉及m个前状态。
因为这道题的代码和斐波那契完全一样,因此就给出m步的代码:
class Solution {
public:
int climbStairs(int n) {
vector<int> dp(n + 1, 0);
dp[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) { // 把m换成2,就可以AC爬楼梯这道题
if (i - j >= 0) dp[i] += dp[i - j];
}
}
return dp[n];
}
};
746. 以最小花费爬楼梯
1. 思路
(1)确定dp数组以及下标的含义
dp数组是到每层楼的最小花费,下标是楼层
这里出现了困扰,核心在于dp数组的定义不清晰。可以定义为到达第i个台阶的花费,台阶从0-n。这样避免了台阶和楼层数的纠缠。最后一个台阶就是楼顶。
(2)确定递推公式
dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2])
(3)dp数组初始化
dp[0] = 0, dp[1] =0
到达第0和1个台阶都可以直接到达,因此没有花费。
(4)确定遍历顺序
应该从左到右遍历
(5)举例推导dp数组
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
if(cost.size()==2){
return min(cost[0],cost[1]);
}else if(cost.size()==1){
return cost[0];
}
vector<int> dp(cost.size()+1);
dp[0] = 0;
dp[1] = 0;
for(int i=2; i<dp.size(); i++){
dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2]);
}
return dp[dp.size()-1];
}
};