题目:494. 目标和
思路
01背包
转换为01背包问题
难点在于看出可以用背包问题解决本题;
题目字面意思是划分出一堆再减去另一堆,得到的结果想要等于target
,设定一堆为正,记为left
,另一堆为负,记为right
,所有数的和为sum
。
有left + right = sum
,left - right = target
,解得left = (target + sum) / 2
,right = (sum - target) / 2
,因为left
是一个整数,所以target + sum
必须为偶数,同时right
为正数,所以sum - target
也必须为正;
01背包
f[j]
:区间[0, i]
的数字放进容积为j
的背包里,有f[j]
这么多种放法;- f [ j ] = ∑ i = 0 i f [ j − n u m s [ i ] ] f[j] =\sum_{i = 0}^i{f[j - nums[i]]} f[j]=∑i=0if[j−nums[i]],在保证
j - nums[i]
有效性的前提下,这是一个组合问题,相当于在前面一个的基础上选nums[0]
,或者选nums[1]
,… … 或者选nums[i]
,最后把这些情况都加起来; f[0] = 0
;weights[i] = nums[i],values[i] = nums[i]
代码
// 01背包
// f[j] : [0, i]这个区间的数放进容量为j的背包里,有几种方法
// f[j] = sum(f[j - nums[i]])
// weights[i] = nums[i], values[i] = nums[i];
// f[0] = 1
// 注意 target 有可能为负数
class Solution {
public:int findTargetSumWays(vector<int>& nums, int target) {int i, j;int size = nums.size(), sum = 0;int f[1005] = {0};f[0] = 1;for(i = 0; i < size; i++){sum += nums[i];}cout << "sum : " << sum;// 不合法if((target + sum) % 2 == 1 || sum < abs(target)){return 0;}for(i = 0; i < size; i++){for(j = sum; j >= nums[i]; j--){f[j] += f[j - nums[i]];}}return f[(sum + target)/2];}
};