我现在每天都在用从代码随想录学到的方法去尝试自己解题,希望算法能力可以尽快提上去。骑马找马,一边工作一边找工作,希望可以尽快成功上岸。每天都在这样不停的祈祷上帝。
一、最后一块石头的重量II
leetcode题目链接:1049.最后一块石头的重量II
题目描述:
有一堆石头,用整数数组
stones
表示。其中stones[i]
表示第i
块石头的重量。每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为
x
和y
,且x <= y
。那么粉碎的可能结果如下:
- 如果
x == y
,那么两块石头都会被完全粉碎;- 如果
x != y
,那么重量为x
的石头将会完全粉碎,而重量为y
的石头新重量为y-x
。最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回
0
。
解题思路大概了解一下吧:
将石头尽可能的分成两堆。相撞之后就是最小值了。重量总和近似相等的两堆。
每个物品只能用一次,0-1背包问题
动归五部曲:
1、dp[i],容量j,最大价值为dp[j];对于本体来说,价值就是重量,重量就是价值。
2、递推公式:
dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i])
对于本题:
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i])
3、初始化
dp[0] = 0;
dp[1501] = 0;
4、遍历顺序
第一层i遍历物品
第二层j遍历背包,从大往小遍历,target = Math.floor(sum / 2) ;
5、打印dp数组
结果为:sum - dp[target] - dp[target] ;
完整版的代码:
var lastStoneWeightII = function (stones) {
let sum = stones.reduce((s, n) => s + n);
let dpLen = Math.floor(sum / 2);
let dp = new Array(dpLen + 1).fill(0);
for (let i = 0; i < stones.length; ++i) {
for (let j = dpLen; j >= stones[i]; --j) {
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
return sum - dp[dpLen] - dp[dpLen];
};
二、目标和
leetcode题目链接:494.目标和
题目描述:
给你一个非负整数数组
nums
和一个整数target
。向数组中的每个整数前添加
'+'
或'-'
,然后串联起所有整数,可以构造一个 表达式 :
- 例如,
nums = [2, 1]
,可以在2
之前添加'+'
,在1
之前添加'-'
,然后串联起来得到表达式"+2-1"
。返回可以通过上述方法构造的、运算结果等于
target
的不同 表达式 的数目。
注意看一下代码:
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
const findTargetSumWays = (nums, target) => {
const sum = nums.reduce((a, b) => a+b);
if(Math.abs(target) > sum) {
return 0;
}
if((target + sum) % 2) {
return 0;
}
const halfSum = (target + sum) / 2;
let dp = new Array(halfSum+1).fill(0);
dp[0] = 1;
for(let i = 0; i < nums.length; i++) {
for(let j = halfSum; j >= nums[i]; j--) {
dp[j] += dp[j - nums[i]];
}
}
return dp[halfSum];
};
三、一和零
leetcode题目链接:474.一和零
题目描述:
给你一个二进制字符串数组
strs
和两个整数m
和n
。请你找出并返回
strs
的最大子集的长度,该子集中 最多 有m
个0
和n
个1
。如果
x
的所有元素也是y
的元素,集合x
是集合y
的 子集 。
二维dp数组,有三个变量
1、确定dp数组的含义
装满i个0,j个1,最多背了多少个物品,dp[i][j];即dp[m][n]。
2、确定递推公式
纯零一背包的递推公式:dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i])
假设物品里面有x个0,y个1.
本题的递推公式:dp[i][j] = Math.max(dp[i - x][j - y] + 1, dp[i][j])
3、初始化
dp[0][0] = 0;非零下标也都初始成0;
4、遍历顺序
先物品,后背包,背包要倒序遍历。
5、打印dp数组
来看一下具体的js代码吧:
const findMaxForm = (strs, m, n) => {
const dp = Array.from(Array(m+1), () => Array(n+1).fill(0));
let numOfZeros, numOfOnes;
for(let str of strs) {
numOfZeros = 0;
numOfOnes = 0;
for(let c of str) {
if (c === '0') {
numOfZeros++;
} else {
numOfOnes++;
}
}
for(let i = m; i >= numOfZeros; i--) {
for(let j = n; j >= numOfOnes; j--) {
dp[i][j] = Math.max(dp[i][j], dp[i - numOfZeros][j - numOfOnes] + 1);
}
}
}
return dp[m][n];
};