一、动态规划理论基础
动态规划,dynamic programming,dp,解决重叠子问题
和贪心的区别在于,动态规划的每个状态是由上一个状态推导出来的,贪心则没有状态推导,而是直接从局部直接选择最优的
动态规划五部曲
- 确定dp数组以及下标的含义
- 确定递推公式
- dp数组如何初始化,(递推公式决定了如何初始化)
- 确定遍历顺序
- 举例推导dp数组
二、斐波那契数
数列0和1开始,后面每一项是前两项的和
五部曲
dp[i]表示第i个斐波那契数- 递推公式:状态转义方程
dp[i] = dp[i-1] + dp[i-2] - 初始化:
dp[0] = 0;dp[1] = 1 - 遍历顺序: 从前往后
- 举例推导dp数组
/**
* @param {number} n
* @return {number}
*/
var fib = function(n) {
let dp = []
dp[0] = 0
dp[1] = 1
for(let i = 2; i <= n;i++) {
dp[i] = dp[i-1] + dp[i-2]
}
return dp[n]
};
简化法
var fib = function(n) {
if(n < 2) {
return n
}
let res
let pre = 0
let cur = 1
for(let i = 2; i <=n ;i++) {
res = pre + cur
pre = cur
cur = res
}
return res
};
递归法
var fib = function(n) {
function dfs(n) {
if(n < 2) {
return n
}
return dfs(n-1) + dfs(n-2)
}
return dfs(n)
};
三、爬楼梯
dp[i]表示第i层楼的方式- 递推公式:状态转义方程
dp[i] = dp[i-1] + dp[i-2] - 初始化:
dp[1] = 1;dp[2] = 2 - 遍历顺序: 从前往后
- 举例推导dp数组
/**
* @param {number} n
* @return {number}
*/
var climbStairs = function(n) {
let dp = []
dp[1] = 1
dp[2] = 2
for(let i = 3; i <= n;i++) {
dp[i] = dp[i-1] + dp[i-2]
}
return dp[n]
};
四、使用最小花费爬楼梯
dp[i]表示第i台阶花费的最少体力- 递推公式:状态转义方程
dp[i] = Math.min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2]) - 初始化:
dp[0] = 0;dp[1] = 0 - 遍历顺序: 从前往后
- 举例推导dp数组
/**
* @param {number[]} cost
* @return {number}
*/
var minCostClimbingStairs = function(cost) {
let dp = []
dp[0] = 0
dp[1] = 0
let len = cost.length
for(let i = 2;i <= len;i++) {
dp[i] = Math.min(dp[i-1] + cost[i-1], dp[i-2]+cost[i-2])
}
return dp[len]
};