LeetCode 1049.最后一块石头的重量II
📖 考察点
动规
📖 题意理解
有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。
每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:
- 如果
x == y,那么两块石头都会被完全粉碎; - 如果
x != y,那么重量为x的石头将会完全粉碎,而重量为y的石头新重量为y-x。
最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0
💡 解题思路
/**
- 1.dp[i][j] 代表 在rang[0,i] 和容量小于等于j的最大值
- 2.dp[i][j] = dp[j] = Math.max(dp[i-1][j], dp[i-1][j - stones[i]] + stones[i]);
- 3.初始化第一行的数值
- 4.便历顺序为从上到下,从左到右;
*/
💻 代码实现
JavaScript
var lastStoneWeightII = function (stones) {
if (stones.length === 1) {
return stones[0];
}
let sum = stones.reduce((p, c) => p + c);
let target = ~~(sum / 2) + 1;
let dp = new Array(target).fill(0);
for (let j = stones[0]; j < target; j++) {
dp[j] = stones[0];
}
for (let i = 1; i < stones.length; i++) {
for (let j = target - 1; j > 0; j--) {
if (j >= stones[i]) {
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
}
return Math.abs(sum - dp[target - 1] * 2);
};
LeetCode 494.目标和
📖 考察点
动规
📖 题意理解
💡 解题思路
/**
- 1.dp[i][j]代表在rang[0,i]里容量为j的背包刚好填满的组合数
- 2.dp[i][j] = dp[i-1][j] + dp[j-nums[i]];
- 3.初始化第一行和第一列
- 4.便历顺序为从上到下,从左到右;
*/
💻 代码实现
JavaScript
var findTargetSumWays = function (nums, target) {
let sum = nums.reduce((p, c) => p + c);
if (((sum + target) & 1) === 1 || Math.abs(target) > sum) {
return 0;
}
let half = (sum + target) / 2;
let dp = new Array(half + 1).fill(0);
if (nums[0] <= half) {
dp[nums[0]] = 1;
}
let numZero = 0;
if (nums[0] === 0) {
dp[0] = 2;
numZero++;
} else {
dp[0] = 1;
}
for (let i = 1; i < nums.length; i++) {
for (let j = half; j > 0; j--) {
if (nums[i] > j) {
dp[j] = dp[j];
} else {
dp[j] += dp[j - nums[i]];
}
}
if (nums[i] === 0) {
numZero++;
dp[0] = 2 ** numZero;
}
}
return dp[half];
};
关键点总结
初始化时如果值为0的情况需要关注
LeetCode474.一和零
📖 考察点
动规 01背包
📖 题意理解
💡 解题思路
/**
- 1.dp[i][j][k] 代表 range[0,i]最多有j个0和k个1的最长子集长度
- 2.dp[i][j][k] = Math.max(dp[i - 1][j][k], dp[i - 1][j - num1][k - num2] + 1);
- 3.初始化i为0时的数组
- 4.便历顺序为从上到下,从左到右;
*/
💻 代码实现
JavaScript
var findMaxForm = function (strs, m, n) {
let dp = new Array(strs.length)
.fill(0)
.map(() => new Array(m + 1).fill(0).map(() => new Array(n + 1).fill(0)));
let [num1, num2] = get01Num(strs[0]);
// 初始化
if (num1 <= m && num2 <= n) {
for (let j = num1; j <= m; j++) {
for (let k = num2; k <= n; k++) {
dp[0][j][k] = 1;
}
}
}
for (let i = 1; i < strs.length; i++) {
let [num1, num2] = get01Num(strs[i]);
for (let j = 0; j <= m; j++) {
for (let k = 0; k <= n; k++) {
if (num1 <= j && num2 <= k) {
dp[i][j][k] = Math.max(dp[i - 1][j][k], dp[i - 1][j - num1][k - num2] + 1);
} else {
dp[i][j][k] = dp[i - 1][j][k];
}
}
}
}
return dp[strs.length - 1][m][n];
};
function get01Num(str) {
let num0 = 0,
num1 = 0;
for (let i = 0; i < str.length; i++) {
if (str[i] === "1") {
num1++;
} else {
num0++;
}
}
return [num0, num1];
}