本文最后更新于:2021年8月14日 上午
给定一个非负整数数组,a1, a2, …, an, 和一个目标数,S。现在你有两个符号 +
和 -
。对于数组中的任意一个整数,你都可以从 +
或 -
中选择一个符号添加在前面。
返回可以使最终数组和为目标数 S 的所有添加符号的方法数。
示例:
| 输入:nums: [1, 1, 1, 1, 1], S: 3 输出:5 解释:
-1+1+1+1+1 = 3 +1-1+1+1+1 = 3 +1+1-1+1+1 = 3 +1+1+1-1+1 = 3 +1+1+1+1-1 = 3
一共有5种方法让最终目标和为3。
|
提示:
- 数组非空,且长度不会超过 20 。
- 初始的数组的和不会超过 1000 。
- 保证返回的最终结果能被 32 位整数存下。
Solution
参考:《算法小抄》2.19
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution: def findTargetSumWays(self, nums: List[int], S: int) -> int: if len(nums)==0: return 0 def backtrack(nums, i, rest): result=0 if i==len(nums): if rest==0: return 1 return 0 rest += nums[i] result+= backtrack(nums, i+1, rest) rest -= nums[i] rest -= nums[i] result+=backtrack(nums, i+1, rest) rest += nums[i] return result
return backtrack(nums, 0, S)
|
参考 carlsun-2
转换成 0-1 背包问题
把所有符号为正的数总和设为一个背包的容量,容量为x;把所有符号为负的数总和设为一个背包的容量,容量为y。在给定的数组中,有多少种选择方法让背包装满。令sum为数组的总和,则x+y = sum。而两个背包的差为S,则x-y=S。从而求得x=(S+sum)/2。
基于上述分析,题目转换为背包问题:给定一个数组和一个容量为x的背包,求有多少种方式让背包装满。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { public: int findTargetSumWays(vector<int>& nums, int S) { int n = nums.size(); int sumAll = 0; for(int num : nums) sumAll += num; if(sumAll<S || (sumAll+S)%2==1) return 0; int sum = (sumAll+S)/2; vector<int> dp(sum+1, 0); dp[0] = 1; for(int i=0; i<n; ++i){ for(int j=sum; j>=nums[i]; --j) dp[j] += dp[j-nums[i]]; } return dp[sum]; } };
|