题目如下:
You are given a list of non-negative integers, a1, a2, …, an, and a target, S. Now you have 2 symbols + and -. For each integer, you should choose one from + and - as its new symbol.
Find out how many ways to assign symbols to make sum of integers equal to target S.Example 1:
1
2
3
4
5
6
7
8
9 Input: nums is [1, 1, 1, 1, 1], S is 3.
Output: 5
Explanation:
-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
There are 5 ways to assign symbols to make the sum of nums be target 3.
Note:
- The length of the given array is positive and will not exceed 20.
- The sum of elements in the given array will not exceed 1000.
- Your output answer is guaranteed to be fitted in a 32-bit integer.
题目大意
给定一个正数数组以及一个整数S,现在有两个符号+
和-
,对于数组里面的每一个数字,你可以选择+
或者-
作为它的新符号,找出所有选择符号的方式,使这些数字和为S。简单来说,给定一个数组,每个数可以加或者减,求出所有能使这些数字加减和为S的组合数。如{1,1,1,1,1}
,S为3,那么一共有5种方法使得这些数字和为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
+1+1+1+1-1 = 3
思路
假设数组中所有数字之和为sum
。根据使用的符号不同,我们可以将数组内数字分为2组P
和N
,如数组{1,2,3}
,目标为0,那么显然有如下选择方式:
+1+2-3 = 0
那么其中P={1,2},N={3}
。那么sum(P)-sum(N)=S
,并且sum(P)+sum(N)=sum
。由此可以推出S+sum=sum(P)-sum(N)+sum(P)+sum(N)=2*sum(P)
。
这样我们就把原来的问题转换成了一个新的问题,在整个数组中,能否找到一些数字的和为(S+sum)/2
,这就成了一个最经典的0-1背包问题
,这样的话就简单了很多。
这里有一个需要注意的地方,(S+sum)/2
这个数必须为偶数,否则无法得到,其次,S
也必须小于sum
,否则也无法求得。
这个算法的空间复杂度不定,取决于S
和sum
,不过题目限制了sum < 1000
,那么空间复杂度为O(sum)
。至于时间复杂度也取决于sum
,时间复杂度是O(sum*N2)。Java
版的代码如下:
1 | public int findTargetSumWays(int[] nums, int S) { |
提交结果如下:
总结
最近在刷Leetcode
上的tag
为动态规划的题,做了那么多其实动态规划的思想一直没变,最重要的是找到状态、状态转移公式以及转移状态的条件。当然,有的时候还需要一些数学推导,把当前不熟悉的问题转化成熟悉的问题。
```