建设银行快审额度查询网站/东莞seo建站排名
题目
给定一个非负整数数组,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 位整数存下。
动态规化
这题可以转换为第416分割子集的问题。
将数组nums分为两部分正数P,负数N:
P - N = SP + N + P - N = S + P + NP = (S + P + N) / 2P = (S + sum)/2
因此只需要找到一个子集令其都为正号其和刚好为(S + sum)/2
就说明存在解。这题需注意nums数组中元素为非负整数,而416题为正整数。所以需要注意j
可以为0
class Solution {public int findTargetSumWays(int[] nums, int S) {// P - N = S// P + N + P - N = S + P + N// P = (S + P + N) / 2// P = (S + sum)/2 int sum = Arrays.stream(nums).sum();if (sum < S || (sum + S) % 2 == 1) {return 0;}int target = (S + sum) / 2;int n = nums.length;// 考虑第[0, i)个数能否刚好填满容量为j 的背包的方法数int[][] dp = new int[n + 1][target + 1];// i= 0 j!=0, dp[0][j] = 0, j = 0,i==0, dp[i][0] = 1dp[0][0] = 1;for (int i = 1; i < n + 1; i++) {for (int j = 0; j < target + 1; j++) {if (nums[i - 1] <= j) {dp[i][j] = dp[i-1][j] + dp[i-1][j - nums[i-1]];} else {dp[i][j] = dp[i-1][j];}}}return dp[n][target];}
}
空间优化
class Solution {public int findTargetSumWays(int[] nums, int S) {// P - N = S// P + N + P - N = S + P + N// P = (S + P + N) / 2// P = (S + sum)/2 int sum = Arrays.stream(nums).sum();if (sum < S || (sum + S) % 2 == 1) {return 0;}int target = (S + sum) / 2;int n = nums.length;// 考虑第[0, i)个数取数能否刚好填满容量为j 的背包的方法数int[] dp = new int[target + 1];dp[0] = 1;if (nums[0] <= target)dp[nums[0]] += 1;// 注意是+=,nums[0]可以为0for (int i = 1; i < n; i++) {for (int j = target; j >= 0; j--) {if (nums[i] <= j) {dp[j] = dp[j] + dp[j - nums[i]];}}}return dp[target];}
}
dfs
数组长度不会超过20,20个数字的序列,组合方式撑死了2202^{20}220
种,算下来才1024 × 10241024×1024, 对于每一个数S都能加上这个数或者减去这个数,当到达叶子节点时判断S是否为0如果为0则返回1,最后将所有情况累加返回。
class Solution {public int findTargetSumWays(int[] nums, int S) {return dfs(nums, 0, S);}private int dfs(int[] nums, int start, int sum) {if (start == nums.length) {return sum == 0 ? 1 : 0;}return dfs(nums, start + 1, sum - nums[start]) +dfs(nums, start + 1, sum + nums[start]);}
}