给定一个非负整数数组,a1, a2, …, an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。
返回可以使最终数组和为目标数 S 的所有添加符号的方法数。
leetcode
解题思路:
- 首先想到的是暴力深搜,枚举每一种做法,这样时间复杂度是n方的,也没有什么意义。
- 可以采用动态规划的思想。设负数和为y,正数和为x,则有 x + y = S,还有x - y = sum,sum是数组中所有元素的累加。这样可以得到 x = (S + sum) / 2,于是将问题转化为了一个01背包问题。
class Solution {
public int findTargetSumWays(int[] nums, int s) {
int sum = 0;
for(int n : nums) sum += n;
// 因为不存在小数,正数和一定是偶数,所以,如果是奇数就直接返回0
if((sum + s) % 2 == 1) return 0;
// 全部都为正数还每目标值大,那就没必要算了
if(s > sum) return 0;
int len = (sum + s) / 2;
int[] f = new int[len + 1];
f[0] = 1;
// 01背包,先枚举物品,再从高到底枚举和
for(int n : nums) {
for(int i = len; i >= n; i--) {
f[i] += f[i - n];
}
}
return f[len];
}
}