1049. 最后一块石头的重量 II
思路:
尽量分成重量相等的两堆石头,相撞即得到剩余最小可能重量
转化成背包问题:石头的重量也是价值,总体重量的一半就是背包的容量。
递归五部曲:
- dp[j]表示 背包总容量(所能装的总重量)是j,放进物品后,背的最大重量为dp[j]。
- dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);
- 重量和价值不会为负数,所以初始化为0即可
class Solution {
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for (int i = 0; i < stones.length; i++) {
sum += stones[i];
}
int target = sum / 2;
int[] dp = new int[target + 1];
for (int i = 0; i < stones.length; i++) {
for (int j = target; j >= stones[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
return sum - dp[target] - dp[target];
}
}
思路:
转化为背包问题
- lefts - rights = target
- lefts + rights = sum -> rights = sum - lefts
- lefts - (sum - lefts) = target -> 2lefts = target + sum
- lefts = (target + sum) / 2
- 此时问题转换为 容量为 (target + sum) / 2 的背包有几种装法
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for (int num : nums) {
sum += num;
}
if (Math.abs(target) > sum) return 0;
if ((sum + target) % 2 != 0) return 0;
int bagSize = (sum + target) / 2;
int[] dp = new int[bagSize+1];
for (int i = 0; i < nums.length; i++) {
for (int j = bagSize; j >= nums[i]; j++) {
// dp[i] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
dp[j] += dp[j - nums[i]];
}
System.out.println(Arrays.toString(dp));
}
return dp[bagSize];
}
- dp[i][j]:最多有i个0和j个1的strs的最大子集的大小为dp[i][j]。
- dp[i][j] 就可以是 dp[i - zeroNum][j - oneNum] + 1。
- 然后我们在遍历的过程中,取dp[i][j]的最大值。
- 所以递推公式:dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
- 因为物品价值不会是负数,初始为0,保证递推的时候dp[i][j]不会被初始值覆盖。
- 01背包一定是外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历!
- 那么本题也是,物品就是strs里的字符串,背包容量就是题目描述中的m和n。
- 举例推导dp数组
public int findMaxForm(String[] strs, int m, int n) {
//dp[i][j]表示i个0和j个1时的最大子集
int[][] dp = new int[m+1][n+1];
int oneNum, zeroNum;
for (String str : strs) {
oneNum = 0;
zeroNum = 0;
for (char ch: str.toCharArray()) {
if (ch == '0') {
zeroNum++;
} else {
oneNum++;
}
}
// 倒序遍历
for (int i = m; i >= zeroNum; i--) {
for (int j = n; j >= oneNum; j--) {
dp[i][j] = Math.max(dp[i][j], dp[i-zeroNum][j-oneNum] + 1);
}
System.out.println(Arrays.toString(dp[i]));
}
}
return dp[m][n];
}