摘要
本文主要介绍了动态规划的理论基础,以及LeetCode动态规划的几个题目,包括509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯。
1、动态规划理论基础
1.1 概念
什么是动态规划
动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。
所以动态规划中每一个状态一定是由上一个状态推导出来的。
动态规划的解题步骤
dp
数组以及下标的含义- 递推公式
dp
数组如何初始化dp
数组遍历顺序- 打印
dp
数组
动规规划的常见类型
- 动规基础
- 背包问题
- 打家劫舍
- 股票问题
- 子序列问题
2、509.斐波那契数
2.1 思路
dp
数组以及下标的含义:第i个数的斐波那契数值是dp[i]- 递推公式:dp[i] = dp[i-1] + dp[i-2];
dp
数组如何初始化:dp[0] = 0; dp[1] = 1;dp
数组遍历顺序:dp[i]是依赖 dp[i - 1] 和 dp[i - 2],所以是从前往后遍历- 打印
dp
数组
2.2 代码
public int fib(int n) {
if(n == 0 || 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];
}
return dp[n];
}
3、70. 爬楼梯
3.1 思路
-
dp
数组以及下标的含义:爬到第i个台阶有dp[i]种不同的方法可以爬到楼顶 -
递推公式:
- 上i-1层楼梯,有dp[i - 1]种方法,上i-2层楼梯,有dp[i - 2]种方法
- 所以dp[i] = dp[i-1] + dp[i-2];
-
dp
数组如何初始化:dp[0] = 0; dp[1] = 1; dp[2] = 2; -
dp
数组遍历顺序:dp[i]是依赖 dp[i - 1] 和 dp[i - 2],所以是从前往后遍历 -
打印
dp
数组
3.2 代码
public int climbStairs(int n) {
if(n <= 2) {
return n;
}
int[] dp = new int[n+1];
dp[0] = 0;
dp[1] = 1;
dp[2] = 2;
for(int i=3; i<=n; i++) {
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
4、746. 使用最小花费爬楼梯
4.1 思路
-
dp
数组以及下标的含义:爬到第i个台阶的最低花费为dp[i] -
递推公式:
- 上i-1层楼梯,最低花费为dp[i-1],上i-2层楼梯,最低花费为dp[i-2]
- 所以dp[i] = Math.min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2]);
-
dp
数组如何初始化:- 从下标为 0 或下标为 1 的台阶开始,因此支付费用为0;
- dp[0] = 0; dp[1] = 0;
-
dp
数组遍历顺序:dp[i]是依赖 dp[i-1] 和 dp[i-2],所以是从前往后遍历 -
打印
dp
数组
4.2 代码
public int minCostClimbingStairs(int[] cost) {
int len = cost.length;
if(len < 2) {
return 0;
}
int[] dp = new int[len+1];
dp[0] = 0;
dp[1] = 0;
for(int i=2; i<=len; i++) {
dp[i] = Math.min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2]);
}
return dp[len];
}