某个男人 动态规划,而我作为一个致力称为厨师界最会写算法的前端,总得刷上一部分题,有那么一点发现吧,现在我们就来聊聊,菜鸡如我,发现了什么。
汇总这周学习的现在,我脑壳疼的慌,啥东西都想不到,但是为了不破自己每周都总结一下下的目标,只能水几句了;
dp 好像是所有初级菜鸟的一个瓶颈,反正每次说到算法难在哪里,第一个想到的就是 dp, 去吹牛皮说面试别人装逼,就说随手甩几道 dp 去难为面试者的老哥层出不穷,所以 dp 有一种绝望之巅的赶脚,只要翻过它,就能进阶了;
其实学习算法到面试遇到的算法,用到 dp 的时候其实没有,树,链表这些反而是超火的热题,所以 dp 对于前端以面试为目的的算法学习,属于一种积累吧,就是经典题型学一学,遇到了原题搞一搞,遇到难题直接 pass ,就是高考数学倒数两题的感觉,所以呢,所以把最经典的复习一遍,然后。。我就一菜鸡,我也不知道, 反正后续应该会继续编吧,会学更深的 dp,毕竟这个东西是真的有意思,有兴趣的可以到这里学习一下大神的总结
以上,实在吹不下去了,下线,睡觉;下周做,位运算吧;加油呀
分析:
var maxProfit = function(prices) {
let dp_0 = 0,dp_1 = prices[0]
for(let i = 0;i<prices.length;i++){
dp_0 = Math.max(dp_0,dp_1+prices[i])
dp_1 = Math.max(dp_1,-prices[i]) // 因为只会买卖一次,这里
}
return dp_0
}
分析
var maxProfit = function(prices) {
const dp = new Array(prices).map(() => [])
dp[0][0] = 0,dp[0][1] =prices[0]
for (let i = 1; i < prices.length; i++) {
dp[i][0] = Math.max(dp[i-1][1]+prices[i], dp[i-1][0])
dp[i][1] =Math.max( dp[i-1][1], dp[i-1][0]-prices[i])
}
return dp[prices.length-1][0]
};
分析 -- 压缩空间变量
var maxProfit = function(prices) {
let dp_0 = 0,dp_1 = -prices[0]
for (let i = 1; i < prices.length; i++) {
const temp_0 = dp_0
dp_0 = Math.max(dp_0,dp_1+prices[i])
dp_1 = Math.max(temp_0-prices[i],dp_1)
}
return dp_0
}
分析
参考视频:传送门
var maxProfit = function (prices) {
const dp = Array.from(prices).map(() => Array.from({length:2}).map(() => new Array(3)))
const len = prices.length
for(let i = 0;i<len;i++){
for(let k = 1;k<=2;k++){
// base case 1 -- 当 k 为 0 时
dp[i][0][0] = 0
dp[i][1][0] = 0 // 只要交易次数没涨上去,任何交易都是耍流氓
if(i === 0){
// base case 2 -- 第一天时的状态
dp[0][0][k] = 0 //
dp[0][1][k] = -prices[0]
continue
}
dp[i][0][k] = Math.max(dp[i-1][0][k],dp[i-1][1][k]+prices[i])
dp[i][1][k] = Math.max(dp[i-1][1][k],dp[i-1][0][k-1]-prices[i])
}
}
return dp[len-1][0][2]
}
var maxProfit = function(k, prices) {
const len = prices.length
if(len<2) return 0
// dp[i][j][k] -- i 为 [0,len-1] j:0,1 ; k 为 [0,k]
const dp =Array.from(prices).map(() => Array.from({length:2}).map(() => new Array(k+1).fill(0)))
for (let i = 0; i < prices.length; i++) {
// base case1 -- 交易次数为 0 的时候
dp[i][0][0] = 0
dp[i][1][0] = 0
for (let j = 1; j <= k; j++) {
if(i === 0){
// base case2 -- 第一天交易
dp[0][0][j] = 0
dp[0][1][j] = -prices[0]
continue
}
dp[i][0][j] = Math.max(dp[i-1][0][j],dp[i-1][1][j]+prices[i])
dp[i][1][j] = Math.max(dp[i-1][1][j],dp[i-1][0][j-1]-prices[i])
}
}
return dp[prices.length-1][0][k]
};
分析
var maxProfit = function (prices) {
const len = prices.length;
if (len < 2) return 0;
let dp_0_0 = 0,
dp_0_1 = 0,
dp_1_0 = -prices[0];
for (let i = 1; i < len; i++) {
const temp = dp_0_0;
// 不在冷却中的没持有状态,证明上一次只可能是没有持有的状态
dp_0_0 = Math.max(dp_0_0, dp_0_1);
dp_0_1 = dp_1_0 + prices[i];
dp_1_0 = Math.max(dp_1_0,temp - prices[i]);
}
return Math.max(dp_0_0, dp_0_1);
};
console.log(maxProfit([1, 2, 4]));
分析
var maxProfit = function(prices, fee) {
let dp_0 = 0, dp_1 = -prices[0]
for (let i = 1; i < prices.length; i++) {
const temp =dp_0
dp_0 = Math.max(dp_0,dp_1 + prices[i] - fee)
dp_1 = Math.max(dp_1,temp - prices[i])
}
return dp_0
};
分析
var rob = function (nums) {
const len = nums.length;
const dp = new Array(len).fill(null).map(() => new Array(2));
dp[0][0] = 0;
dp[0][1] = nums[0];
for (let i = 1; i < len; i++) {
dp[i][0] = Math.max(dp[i - 1][1], dp[i - 1][0]);
dp[i][1] = dp[i - 1][0] + nums[i];
}
return Math.max(dp[len - 1][0], dp[len - 1][1]);
};
分析
var rob = function (nums) {
let dp_0 = 0,dp_1 = nums[0]
for (let i = 1; i < len; i++) {
const temp = dp_0 // 保存一下上一个 dp_0
dp_0 = Math.max(dp_0,dp_1)
dp_1 = temp+nums[i]
}
return Math.max(dp_0,dp_1)
}
分析
var rob = function (nums) {
const len = nums.length;
const dp = new Array(len)
.fill(0)
.map(() => new Array(2).fill(0).map(() => new Array(2).fill(-1)));
(dp[0][0][0] = 0), (dp[0][1][1] = nums[0]);
for (let i = 1; i < len; i++) {
dp[i][0][0] = Math.max(dp[i - 1][0][0], dp[i - 1][0][1]);
dp[i][0][1] = dp[i - 1][0][0] + nums[i];
dp[i][1][0] = Math.max(dp[i - 1][1][0], dp[i - 1][1][1]);
dp[i][1][1] = i === len - 1 ? dp[i - 1][1][1] : dp[i - 1][1][0] + nums[i];
}
return Math.max(dp[len - 1][0][0], dp[len - 1][0][1], dp[len - 1][1][0],dp[len - 1][1][1]);
};
分析
var rob = function (nums) {
let dp_0_0 = 0, dp_1_1 = nums[0], dp_1_0 = -1,dp_0_1 = -1
for (let i = 1; i < nums.length; i++) {
const temp_0_0 = dp_0_0
const temp_1_0 = dp_1_0
dp_0_0 = Math.max(dp_0_0,dp_0_1)
dp_0_1 = temp_0_0 + nums[i]
dp_1_0 = Math.max(dp_1_0,dp_1_1)
dp_1_1 = i === nums.length - 1 ? dp_1_1 : temp_1_0+nums[i]
}
return Math.max(dp_0_0,dp_1_1,dp_1_0,dp_0_1);
};
分析
var rob = function (root) {
const recursion = (root) => {
if (!root) return [0, 0];
const [ldp_0, ldp_1] = recursion(root.left);
const [rdp_0, rdp_1] = recursion(root.right);
const dp_0 = Math.max(
ldp_0 + rdp_0,
ldp_0 + rdp_1,
ldp_1 + rdp_0,
ldp_1 + rdp_1
);
const dp_1 = ldp_0 + rdp_0 + root.val;
return [dp_0, dp_1];
};
const [dp_0, dp_1] = recursion(root);
return Math.max(dp_0, dp_1);
};
分析
var generate = function(numRows) {
const dp = new Array(numRows)
for (let i = 0; i < numRows; i++) {
dp[i] = new Array() ;
for(let j = 0;j<=i;j++){
// 杨辉三角的两边都是 1
if(j === 0 || j === i) {
dp[i][j] = 1
continue
}
dp[i][j] = dp[i-1][j-1]+dp[i-1][j]
}
}
return dp
};
console.log(generate(1))
console.log(generate(2))
console.log(generate(5))
分析 -- 记忆化递归 -- 自顶向下缓存对应的值
var climbStairs = function(n) {
const map = new Map()
map.set(1,1)
map.set(0,1)
const recursion= (n) => {
if(map.has(n)) return map.get(n)
const sum = recursion(n-1)+recursion(n-2)
map.set(n,sum)
return sum
}
return recursion(n)
};
@分析 -- dp
var climbStairs = function(n) {
const dp = []
dp[1] = 1
dp[0] = 1
for (let i = 2; i <= n; i++) {
dp[i] = dp[i-1]+dp[i-2]
}
return dp[n]
}
分析
var hanota = function(A, B, C) {
const len = A.length;
const recursion = (n,first,second,end) => {
if(n === 1) {
const a = first.pop()
end.push(a)
return
}
// 将 n-1 个值从 first -> end -> second, 然后将最后的值从 first 移动到 end
recursion(n-1,first,end,second)
end.push(first.pop())
// 现在 end 有一个值, second 有 n-1 个值 , first 为空
// 再将 n-1 个值从 second -> first -> end
recursion(n-1,second,first,end)
}
recursion(len,A,B,C)
};
分析 -- 硬币数无限
var coinChange = function (coins, amount) {
const dp = new Array(amount + 1)
// base case
dp[0] = 0; // 如果总金额为0,则不需要取了
for (let i = 1; i <= amount; i++) {
dp[i] = Infinity //初始化
for (coin of coins) {
if (i >= coin) {
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
}
}
return dp[amount] === Infinity ? -1 : dp[amount];
};
// 两层遍历是无所谓 的,排列组合都 ok,因为求的是一个极值
var coinChange = function (coins, amount) {
const dp = new Array(amount + 1).fill(Infinity);
// base case
dp[0] = 0; // 如果总金额为0,则不需要取了
for (coin of coins) {
for (let i = 1; i <= amount; i++) {
if (i >= coin) {
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
}
}
return dp[amount] === Infinity ? -1 : dp[amount];
};
分析
var change = function (amount, coins) {
const dp = new Array(amount + 1).fill(0); //凑不齐就是 0 个方案了
dp[0] = 1; //不取也是一种方案
// 相当于背包问题中,背包里的东西有哪些,每多一样东西,就可以更新方案
for (coin of coins) {
for (let i = coin; i <= amount; i++) {
// 只有比当前币值高的,才需要更新方案数
dp[i] = dp[i] + dp[i - coin];
}
}
return dp[amount];
};
分析
var longestPalindrome = function(s) {
const dp =Array.from(s).map(() => new Array())
let ret = ''
for(let j = 0;j <s.length;j++){
for(let i =j;i>=0;i--){
if( j-i<2 && s[i] === s[j]){
// base case : 单个字符
dp[i][j] = true
}else if(s[i] === s[j] && dp[i+1][j-1]){
dp[i][j] = true
}
if(dp[i][j] && j-i+1>ret.length){
ret = s.slice(i,j+1)
}
}
}
return ret
};
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。