O(n*target)
把问题转换成真正的类背包问题
原来是每个数+或者-,现在每个数都乘2,这样就变成0个或者1个,也就是加这个数或者不加这个数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Solution { public: int findTargetSumWays(vector<int>& nums, int S) { int sum = accumulate(nums.begin(), nums.end(), 0); if (sum < S) return 0; for_each(nums.begin(), nums.end(), [](int &num){num <<= 1;}); long target = sum + S; vector<vector<int>> f(target + 1, vector<int>(nums.size() + 1)); f[0][0] = 1; for (int i = 0; i <= target; ++i) { for (int j = 1; j < f[i].size(); ++j) { f[i][j] = f[i][j - 1] + (i >= nums[j - 1] ? f[i - nums[j - 1]][j - 1] : 0); } } return f.back().back(); } };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Solution { public: int findTargetSumWays(vector<int>& nums, int S) { int sum = accumulate(nums.begin(), nums.end(), 0); if (sum < S) return 0; for_each(nums.begin(), nums.end(), [](int &num){num <<= 1;}); int target = sum + S, n = nums.size(); vector<vector<int>> f(n + 1, vector<int>(target + 1)); f[0][0] = 1; for (int i = 1; i <= n; ++i) { for (int j = 0; j <= target; ++j) { f[i][j] = f[i - 1][j] + (j >= nums[i - 1] ? f[i - 1][j - nums[i - 1]] : 0); } } return f[n][target]; } };
|
因为转换后的背包问题要求原来的所有数都要double,则新的target = sum + S也必须是个偶数,这样其实不需要修改nums,只需要把新的target除2即可,前提是target必须是偶数
- 原来的每个数放-1个或者1个转换成放0个或者2个
- 目标值从S变成sum + S,因为相当于在原来的每种可能基础上加了一个sum
- 这样相当于每个数都double了,进而变成标准0-1背包问题,即放这个数(原来的2倍)或者不放这个数
- 又因为原来的每个数要不是0个要不是2个,所以最后的目标值必须是偶数,所以可以不需要手动double每个数,仍然可以使用原来的数,只是目标值改成(sum + S) / 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Solution { public: int findTargetSumWays(vector<int>& nums, int S) { long sum = accumulate(nums.begin(), nums.end(), 0); long target = sum + S, n = nums.size(); if (sum < S || target & 1) return 0; target >>= 1; vector<int> f(target + 1); f[0] = 1; for (int x : nums) { for (int t = target; t >= x; --t) { f[t] += f[t - x]; } } return f[target]; } };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { public: int findTargetSumWays(vector<int>& nums, int S) { int sum = accumulate(nums.begin(), nums.end(), 0); int target = sum + S, n = nums.size(); if (sum < S || target & 1) return 0; target >>= 1; int f[target + 1] = {1}; for (int i = 1; i <= n; ++i) { for (int j = target; j >= nums[i - 1]; --j) { f[j] += f[j - nums[i - 1]]; } } return f[target]; } };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Solution { public: int findTargetSumWays(vector<int>& nums, int S) { int sum = accumulate(nums.begin(), nums.end(), 0); if (sum < S) return 0; for_each(nums.begin(), nums.end(), [](int &num){num <<= 1;}); int target = sum + S, n = nums.size(); vector<int> f(target + 1); f[0] = 1; for (int i = 1; i <= n; ++i) { for (int j = target; j >= nums[i - 1]; --j) { f[j] += f[j - nums[i - 1]]; } } return f[target]; } };
|
dp 不转换成背包直接建模,需要用到hashmap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Solution { public: int findTargetSumWays(vector<int>& nums, int S) { int n = nums.size(); vector<unordered_map<int, int>> f(n + 1); f[0][0] = 1; for (int i = 1; i <= n; ++i) { for (auto &&[t, cnt] : f[i - 1]) { f[i][t + nums[i - 1]] += cnt; f[i][t - nums[i - 1]] += cnt; } } return f[n][S]; } };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Solution { public: int findTargetSumWays(vector<int>& nums, int S) { int n = nums.size(); unordered_map<int, int> f; f[0] = 1; for (int i = 1; i <= n; ++i) { unordered_map<int, int> g; for (auto &&[t, cnt] : f) { g[t + nums[i - 1]] += cnt; g[t - nums[i - 1]] += cnt; } f = g; } return f[S]; } };
|