一、509. 斐波那契数
递推公式已经给出,所以比较简单。注意一下数组的初始化就可以了。
以下是代码部分:
public class 斐波那契数509 {
//递归方法 ——可通过,时间有点长
public int fib(int n) {
if( n == 0)
return 0;
if( n ==1 )
return 1;
return fib(n-1) + fib(n-2);
}
// 动态规划
public int fib2(int n) {
//踩坑,没有判断n=0或1,导致数组越界
if( n == 0)
return 0;
if( n ==1)
return 1;
//1. 确定dp数组,fib(i)。注意,这里大小是 n+1
int[] dp = new int[n+1];
//2. 确定递推公式
//dp[i] = dp[i-1] + dp[i-2]
//3. 初始化dp数组
dp[0] = 0;
dp[1] = 1;
//4. 确定遍历顺序
for (int i = 2; i < dp.length; i++) {
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
}
二、70. 爬楼梯
这道题主要理解递推公式的思想:
爬第n阶楼梯的方法数量,等于 2 部分之和——
- 爬上 n-1n−1 阶楼梯的方法数量。因为再爬1阶就能到第n阶
- 爬上 n-2n−2 阶楼梯的方法数量,因为再爬2阶就能到第n阶
其实,你会发现递推公式的形式跟斐波那契数一样,唯一需要注意的点是在初始化的时候dp[0] = 1。(这里dp[0]=1其实是没有意义的,所以可以把初始化改为dp[1]=1,dp[2]=2。这样的话就是有意义的)
以下是代码部分:
public class 爬楼梯70 {
@Test
public void test(){
climbStairs(8);
}
public int climbStairs(int n) {
//1.确定dp数组
int[] dp = new int[n+1];
//2.递推公式
// dp[i] = dp[i-1] + (i/2+1)
//3.初始化
//与斐波那契数列的唯一区别:dp[0] = 1
dp[0] = 1;
dp[1] = 1;
//4.遍历顺序
for (int i = 2; i < dp.length; i++) {
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
}
三、746. 使用最小花费爬楼梯
这道题困扰了我很久,核心在于理解:
- 到达第i个台阶顶部所需要的最小费用
- 踏上第i个台阶所需要的最小费用
所谓到达,就是到了第i个台阶的顶部(即第i+1个台阶),此时是不需要必须踩第i个台阶的;而踏上第i个台阶,则是要踩在第i个台阶的,所以一定要加cost[i]。
1. 到达第i个台阶顶部
思路:若要到达第i个台阶顶部(即到第i+1个台阶),有两种方案:
- 从 i-1 阶走两步(dp[i-2] + cost[i-1] )
- 从 i 阶走一步(dp[i-1] + cost[i])
这里为什么是dp[i-2] + cost[i-1]。首先dp[i-2]指到达第i-2个台阶顶部(第i-1个台阶)之前所需要的最小花费,到了i-2顶部,想要到i顶部,要走两步,所以要踩第i-1台阶,花费为cost[i-1]。
以下是代码部分:
public int minCostClimbingStairs2(int[] cost) {
//到达第i个台阶顶部所需要的最小费用
int[] dp = new int[cost.length];
dp[0] = 0;
dp[1] = Math.min(cost[0], cost[1]);
for (int i = 2; i < dp.length; i++) {
dp[i] = Math.min(dp[i-2]+cost[i-1], dp[i-1]+cost[i]);
}
return dp[dp.length-1];
}
2. 踏上第i个台阶
思路:若要踏上第i个台阶,则也有两种方案:
- 从 i-2 阶走两步(dp[i-2] + cost[i] )
- 从 i-1 阶走一步(dp[i-1] + cost[i] )
以下是代码部分:
public int minCostClimbingStairs(int[] cost) {
//踏上第i个台阶所需要的最小费用
//确定dp数组。如果有length+1个台阶的最小费用
int[] dp = new int[cost.length];
//递推公式
//dp[i] += min(cost[i-1] ,cost[i-2]
//初始化dp
dp[0] = cost[0];
dp[1] = cost[1];
//遍历
for (int i = 2; i < dp.length; i++) {
//两种情况,从i-1不走i。从i-2走i
dp[i] += Math.min(dp[i-1] , dp[i-2] + cost[i]);
}
return dp[dp.length-1];
}