1. 如果 sum % 2 === 1, 则肯定无解,因为 sum/2 为小数,而数组全由整数构成,子数组和不可能为小数。
2. 如果 sum % 2 === 0, 需要找到和为 2/sum 的子序列
针对 2,我们要在 nums 里找到满足条件的子序列 subNums。 这个过程可以类比为在一个大篮子里面有 N 个球,每个球代表不同的数字,我们用一小篮子去抓取球,使得拿到的球数字和为 2/sum。那么很自然的一个想法就是,对大篮子里面的每一个球,我们考虑取它或者不取它,如果我们足够耐心,最后肯定能穷举所有的情况,判断是否有解。上述思维表述为伪代码如下:
```
令 target = sum / 2, nums 为输入数组, cur 为当前当前要选择的数字的索引
nums 为输入数组,target为当前求和目标,cur为当前判断的数
function dfs(nums, target, cur)
如果target < 0 或者 cur > nums.length
return false
否则
如果 target = 0, 说明找到答案了,返回true
否则
取当前数或者不取,进入递归 dfs(nums, target - nums[cur], cur + 1) || dfs(nums, target, cur + 1)
```
```
Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.
Note:
因为对每个数都考虑取不取,所以这里时间复杂度是 O(2 ^ n), 其中 n 是 nums 数组长度,
Each of the array element will not exceed 100.
#### javascript 实现
The array size will not exceed 200.
Example 1:
```javascript
varcanPartition=function(nums){
letsum=nums.reduce((acc,num)=>acc+num,0);
if(sum%2){
returnfalse;
}
sum=sum/2;
returndfs(nums,sum,0);
};
Input: [1, 5, 11, 5]
functiondfs(nums,target,cur){
if(target<0||cur>nums.length){
returnfalse;
}
return(
target===0||
dfs(nums,target-nums[cur],cur+1)||
dfs(nums,target,cur+1)
);
}
```
Output: true
不出所料,这里是超时了,我们看看有没优化空间
Explanation: The array can be partitioned as [1, 5, 5] and [11].
leetcode 是 AC 了,但是时间复杂度 O(2 ^ n), 算法时间复杂度很差,我们看看有没更好的。
题目要求给定一个数组, 问是否能划分为和相等的两个数组。
### DP 解法
这是一个典型的背包问题,我们可以遍历数组,对于每一个,我们都分两种情况考虑,拿或者不拿。
在用 DFS 是时候,我们是不关心取数的规律的,只要保证接下来要取的数在之前没有被取过即可。那如果我们有规律去安排取数策略的时候会怎么样呢,比如第一次取数安排在第一位,第二位取数安排在第二位,在判断第 i 位是取数的时候,我们是已经知道前 i-1 个数每次是否取的所有子序列组合,记集合 S 为这个子序列的和。再看第 i 位取数的情况, 有两种情况取或者不取
背包问题处理这种离散的可以划分子问题解决的问题很有用。
1. 取的情况,如果 target-nums[i]在集合 S 内,则返回 true,说明前 i 个数能找到和为 target 的序列