1. 分割等和子集(中等)
地址: https://leetcode-cn.com/problems/partition-equal-subset-sum/
2022/01/19
做题反思:base case 就是 dp[…][0] = true 和 dp[0][…] = false,因为背包没有空间的时候,就相当于装满了,而当没有物品可选择的时候,肯定没办法装满背包。
基本解法:
class Solution {
public boolean canPartition(int[] nums) {
int sum = 0;
for (int num : nums) {
sum += num;
}
if (sum % 2 != 0) {
return false;
}
int n = nums.length;
boolean[][] dp = new boolean [n + 1][sum / 2 + 1];
for (int i = 0; i <= n; i++) {
dp[i][0] = true;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= sum / 2; j++) {
if (j - nums[i - 1] < 0) {
dp[i][j] = dp[i - 1][j];
} else {
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]];
}
}
}
return dp[n][sum / 2];
}
}
状态压缩:
2. 目标和(中等)
地址: https://leetcode-cn.com/problems/target-sum/
2022/01/19
做题反思:
回溯:
DP:
显然 dp[0][…] = 0,因为没有物品的话,根本没办法装背包;dp[…][0] = 1,因为如果背包的最大载重为 0,「什么都不装」就是唯一的一种装法。
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for (int num : nums) {
sum += num;
}
if (sum < Math.abs(target) || (sum + target) % 2 != 0) {
return 0;
}
int n = nums.length;
sum = (sum + target) / 2;
int[][] dp = new int[n + 1][sum + 1];
for (int i = 0; i <= n; i++) {
dp[i][0] = 1;
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= sum; j++) {
if (j - nums[i - 1] < 0) {
dp[i][j] = dp[i - 1][j];
} else {
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i - 1]];
}
}
}
return dp[n][sum];
}
}