所用代码 java
动态规划章节
动态规划,英文:Dynamic Programming,简称DP。动态规划的每一个值都是由上一状态的结果推演出来的。
主要有这些类型的题目:
- dp基础
- 背包问题
- 打家劫舍
- 股票问题
- 子序列问题
动态规划解题分为五步:
- 确定dp数组以及下标的含义
- 确定递推公式 – 重要!!
- dp数组如何初始化
- 确定遍历顺序
- 举例推导dp数组
做动态规划的题目要先把状态转移在dp数组上具体情况模拟一遍,写的代码不通过就打印dp数组,遇到问题问题先思考下面三个问题:
- 这道题目我举例推导状态转移公式了吗?
- 我打印dp数组日志了吗?
- 打印出来的dp数组日志和我想的一样吗?
斐波那契数 LeetCode 509
题目链接:斐波那契数 LeetCode 509 - 简单
思路
递归很简单。
动态规划5步曲:
- 确定dp[i]的含义:dp[i],第i个斐波那契数的值为dp[i]
- 递归公式:dp[i] = dp[i-1] + dp[i-2]
- dp数组如何初始化:dp[0]=1,dp[0]=1
- 遍历顺序:从前向后
- 打印dp数组:用于debug
class Solution {
public int fib(int n) {
if (n <= 1)return n;
int[] dp = new int[n+1];
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i-1] + dp[i-2];
// System.out.println(i +" --> "+ dp[i]);
}
return dp[n];
}
}
总结
本题为dp第一个,也比较简单,按5步曲进行推演,可以轻松写出代码。
本题也可以回溯,也很简单。
爬楼梯 LeetCode 70
题目链接:爬楼梯 LeetCode 70 - 简单
思路
动态规划5步曲:
- 确定dp[i]的含义:达到i阶有dp[i]种方法
- 递归公式:dp[i] = dp[i-1] + dp[i-2]
- dp数组如何初始化:dp[0]=0,dp[1]=1,dp[2]=2
- 遍历顺序:从前向后
- 打印dp数组:用于debug
class Solution {
public int climbStairs(int n) {
if (n <= 1) return n;
int[] dp = new int[n+1];
dp[0] = 0;
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i < n+1; i++) {
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
}
总结
该题思路和上一题一样,连式子都一样,也属于简单题。
本题回溯超时。
使用最小花费爬楼梯 LeetCode 746
题目链接:使用最小花费爬楼梯 LeetCode 746 - 中等
思路
费用为往上跳了一步之后才算,而顶楼为cost数组的长度,不是最后一个下标
动态规划5步曲:
- 确定dp[i]的含义:到达i位置的最小花费为dp[i]
- 递推公式:dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2]) 最小花费
- dp数组初始化:dp[0]=0, dp[1]=0
- 遍历方向:左 -> 右
- 打印dp数组:
class Solution {
public int minCostClimbingStairs(int[] cost) {
int[] dp = new int[cost.length + 1];
// 从下标为0或是下边为1开始,没跳的时候费用为0
dp[0] = 0;
dp[1] = 0;
for (int i = 2; i < cost.length + 1; i++) {
// 到达i位置的花费 = i-1的花费+往上跳的花费 和 i-2的花费+往上跳的花费 取最小值
dp[i] = Math.min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2]);
// System.out.println("i = " + i + " dp[i] = " + dp[i]);
}
return dp[cost.length];
}
}
总结
本题的初始化是当下标为0或1我们都不用花费的,再次继续向上跳的时候才开始有花费。