爬楼梯 一次 1 步或者 2 步 到达 100阶 楼梯可以有多少种走法
f(99) + f(98) +。。。。+ f(1)
javascript
const climbStairs = function(n) {
if(n === 1) {
return 1;
}
if(n === 2) {
return 2;
}
return climbStairs(n - 1) + climbStairs(n - 2);
};
会发现 f(99) = f(98) +f(97) f(98) 被算了两次 没必要 空间换时间一下
javascript
const hash = {};
const climbStairs = function(n) {
if(n === 1) {
return 1;
}
if(n === 2) {
return 2;
}
if(hash[n]) {
return hash[n];
} else {
const res = climbStairs(n - 1) + climbStairs(n - 2);
hash[n] = res;
return res;
}
};
至底向上的动态规划
javascript
/**
* @param {number} n
* @return {number}
*/
const climbStairs = function(n) {
let res = 0;
const hash = {1: 1, 2: 2};
for(let i = 3; i < n+1; i++) {
hash[i] = hash[i-1] + hash[i-2]
}
return hash[n]
};
硬币
javascript
const coinChange = function(coins, amount) {
const hash = [0];
for(let i = 1; i < amount + 1; i++) {
hash[i] = Infinity;
for(let coinLength = 0; coinLength < coins.length; coinLength ++) {
const res = i - coins[coinLength];
if(res >= 0) {
hash[i] = Math.min(hash[i], hash[res] + 1);
}
}
}
console.log(hash);
return hash[amount] !== Infinity ? hash[amount] : -1;
};
背包
假设 c 被塞满 一共是 n 个物品 第 n 个物品只有可能 0 1 也就是放进去或者没放进去
假设 f(n, c) 代表最大值
那么 第 n 个包包没装进去 就是 f(n-1, c)
第 n 个被装进去就是 f(n - 1, c - w[n]) + v[n]
那么 f(n,c) = Math.max(f(n-1), f(c- w[n]) + v[n])
javascript
// 入参是物品的个数和背包的容量上限,以及物品的重量和价值数组
function knapsack(n, c, w, value) {
// dp是动态规划的状态保存数组
const dp = (new Array(c+1)).fill(0)
let res = -Infinity;
for(let i = 1; i <= n; i ++) {
for(let j = c; j >= w[i]; j --) {
dp[j] = Math.max(dp[j], dp[j - w[i]] + value[i])
if(dp[j] > res) {
res = dp[j]
}
}
}
return res
}
最长子序列
javascript
const arr = [10,9,2,5,3,7,101,18];
/**
* @param {number[]} nums
* @return {number}
*/
// 入参是一个数字序列 最长上升子序列
const lengthOfLIS = function(nums) {
const len = nums.length;
if(!len) return 0;
const dp = (new Array(len)).fill(1);
let res = 1;
for(let i = 1; i < len; i++) {
for(let j = 0; j < i; j++) {
if(nums[j] < nums[i]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
if(dp[i] > res) {
res = dp[i];
}
}
}
}
return res;
}