动规理论: 动规基础问题:斐波那契数列、背包问题、打家劫舍、股票问题、子序列问题
动规本质性的问题:动规步骤(动规五部曲,见下)
①dp[]数组以及下标i的含义;
②递推公式;
③初始化:dp[]数组如何初始化?和dp[]数组定义有关;
④遍历顺序:背包问题中背包、物品先后遍历顺序,排列问题/组合问题;
⑤打印dp[]数组;
LeetCode:509. 斐波那契数 - 力扣(LeetCode)
1.思路 可以采用公式进行模拟。动规就是在这个基础上的抽象,其中初始化为0 时数组大小为[n + 1]. 2.代码实现
// 动规五部曲
class Solution {
public int fib(int n) {
// ①定义:dp[i] 表示第 i 个数字的大小
int[] dp = new int[n + 1]; // '0'也算个坑,因此要+1
// ②:初始化
dp[0] = 0;
dp[1] = 1;
// ③递推公式:dp[i] = dp[i - 1] + dp[i - 2];
// ④遍历顺序
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[ i - 2];
}
return dp[n];
}
}
// 模拟
class Solution {
public int fib(int n) {
if (n < 2) {
return n;
}
int a = 0, b = 1, c = 0;
for (int i = 2; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
return c;
}
}
3.复杂度分析 时间复杂度:O(n).
空间复杂度:O(n).
LeetCode:70. 爬楼梯 - 力扣(LeetCode)
1.思路 和上一题爬楼梯思路一致,但初始化容易有歧义。 2.代码实现
// 初始化存在问题
class Solution {
public int climbStairs(int n) {
// 找规律
// dp[i] 表示i阶台阶有dp[i]种方法
int[] dp = new int[n + 1]; // 之所以是 n + 1,有个0存在
// 初始化:存在问题
dp[0] = 1; // n >= 1, 理论上讲dp[0]没有意义,在这就是辅助的数值而已
dp[1] = 1;
if ( n < 2) {
return n;
}
// 确定遍历顺序及递推公式
// i 必须从2开始,因为后面的数要用到dp[2],不然就少了dp[2]这个数,必然误解
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}
// 初始化0,1位置上的数(理论上将不正确)
class Solution {
public int climbStairs(int n) {
int a = 1, b = 1, c = 0;
if (n <= 2) {
return n;
}
for (int i = 2; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
return c;
}
}
// 变参(改变初始化内容)
class Solution {
public int climbStairs(int n) {
int a = 1, b = 2, c = 0;
if (n <= 2) {
return n;
}
for (int i = 3; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
return c;
}
}
3.复杂度分析 时间复杂度:O(n).
空间复杂度:O(n).
LeetCode:746. 使用最小花费爬楼梯 - 力扣(LeetCode)
1.思路 dp[i]数组的定义:爬到第i个台阶的最小花费,该题目在上面两个题目的基础之上做了相应的变化,主要体现在条件:第一个和第零个都不需要消费cost,也即两者均初始化为0,这使得当前结果由前一结果和前前一结果推理出来,递推公式就这么产生的。 2.代码实现
class Solution {
public int minCostClimbingStairs(int[] cost) {
// 到达第 i 个台阶最小消费dp[i]
int[] dp = new int[cost.length + 1];
// 初始化:第0和第1个台阶花费都是0
dp[0] = 0;
dp[1] = 0;
// 递推公式:从前一个或前前一个种选择一个较小值
for (int i = 2; i <= cost.length; i++) {
dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
System.out.println(dp[i]);
}
return dp[cost.length];
}
}
3.复杂度分析 时间复杂度:O(n).
空间复杂度:O(n).