题目:
将子数组求和,然后将和除以2,转化找到数组一个子集为总和的一半,即为 0-1 背包问题
dp[i][j] 表示从数组的 [0,i] 下标范围内选取若干个正整数(可以是 0 个),是否存在一种选取方案使得被选取的正整数的和等于 j。初始时,dp 中的全部元素都是 false。
初始化:
- 如果不选取任何正整数,则被选取的正整数之和等于 0。因此对于所有 0 ≤ i < n,都有 dp[i][0]=true。
- 当 i==0 时,只有一个正整数 nums[0] 可以被选取,因此 dp[0]nums[0]]=true。
状态转移:
dp[i][j] = dp[i−1][j] ∣ dp[i−1][j−nums[i]] (j >= nums[i])
dp[i][j] = dp[i-1][j] (j < nums[i])
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include <vector> using std::vector;
class Solution { public: bool canPartition(vector<int> &nums) { int i, j, n = nums.size(); int sum = 0, target;
for (i = 0; i < n; i++) sum += nums[i];
if (sum % 2 != 0) return false;
target = sum / 2;
for (i = 0; i < n; i++) { if (nums[0] > target) return false; }
vector<vector<bool> > dp(n, vector<bool>(target + 1, false));
for (i = 0; i < n; i++) dp[i][0] = true; dp[0][nums[0]] = true;
for (i = 1; i < n; i++) { for (j = 1; j <= target; j++) { if (j >= nums[i]) dp[i][j] = dp[i - 1][j] | dp[i - 1][j - nums[i]]; else dp[i][j] = dp[i - 1][j]; } }
return dp[n - 1][target]; } };
|