1049. 最后一块石头的重量 II
题目链接:1049. 最后一块石头的重量 II
思路:
这题的思路和416.分割等和子集类似,最优的情况是将石头分成两堆,每一堆的重量相同,都是总重量的一半。
动规五部曲
1.确定dp数组以及下标的含义
dp[i][j]的定义为:在容量为j的情况下,从前i个石头中能取到的最大重量。
2.确定递推公式
状态转移方程 dp[i] = Math.max(dp[i - 1][j], dp[i - 1][j - stones[i]] + stones[i];
3.dp数组如何初始化
和01背包类似
4.确定遍历顺序
二维数组从右向左遍历
5.举例推导dp数组
class Solution {
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for (int i : stones) {
sum += i;
}
int target = sum / 2;
// dp数组的含义: 0 ~ i范围内任取数字,在容量为j的情况下,能取到的最大总和
int[][] dp = new int[stones.length][target + 1];
// 初始化
for (int j = stones[0]; j <= target; j++) {
dp[0][j] = stones[0];
}
for (int i = 1; i < stones.length; i++) {
for (int j = 1; j <= target; j++) {
if (j >= stones[i]) {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - stones[i]] + stones[i]);
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
return (sum - dp[stones.length - 1][target]) - dp[stones.length - 1][target];
}
}
494. 目标和
题目链接:494. 目标和
思路:
target值由数组的一部分数与另一部分数相减得到。
left - right = target, left + right = sum
left - (sum - left) = target
left = (sum + target) / 2
题目转换为装满大小为left的背包有多少种方法。
动规五部曲
1.确定dp数组以及下标的含义
dp[j]的定义为:装满容量j的方法数量。
2.确定递推公式
dp[j] += dp[j - nums[i]];
3.dp数组如何初始化
dp[0] = 1
4.确定遍历顺序
一维数组从左向右遍历
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for (int i : nums) {
sum += i;
}
if (Math.abs(target) > sum) return 0;
if ((target + sum) % 2 != 0) return 0;
int size = (target + sum) / 2;
// dp的含义: dp[j]表示填满容量为j的包,有多少种方法
int[] dp = new int[size + 1];
// 初始化
dp[0] = 1;
for (int i = 0; i < nums.length; i++) {
for (int j = size; j >= nums[i]; j--) {
// 不拿nums[i]的情况下,填满容量为j的背包,有dp[j]种方法
// 拿nums[i]的情况下,填满容量为j的背包,有dp[j - nums[i]]种方法
dp[j] = dp[j] + dp[j - nums[i]];
}
}
return dp[size];
}
}