题目:
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:
- Each of the array element will not exceed 100.
- The array size will not exceed 200.
Example 1:
Input: [1, 5, 11, 5]
Output: true
Explanation: The array can be partitioned as [1, 5, 5] and [11].
Example 2:
Input: [1, 2, 3, 5]
Output: false
Explanation: The array cannot be partitioned into equal sum subsets.
题目大意:
这道题目意思是给定一个正整数的数组,问我们这个数组能不能分成两个非空子集合,使得两个子集合的元素之和相同。
解题思路:
采用动态规划的思想,将这个问题抽象成一个背包问题,也就是说给定n个数,第i个数价值为nums[i]。定义一个大小为sum/2(sum为数组中所有元素的和)
的数组,然后根据状态转移方程f[v]=max{f[v],f[v-c[i]]+w[i]}计算出f[sum/2],然后判断f[sum/2]是否等于sum/2,是的话,返回true,否则,返回false;
算法:
1、求出数组的和sum,而且判断sum是否为偶数,不为偶数的话显然不能对半分,这个时候返回false即可,
2、若sum的值为偶数,则定义一个大小为sum/2+1的数组f,并初始化为0;
3、然后用一个二重循环,外层循环是i-n(n为数组大小),内层循环则是从sum/2到0,这里顺序不能颠倒,这样使用内层循环可以节省空间,然后根据状态转移方程f[v]=max{f[v],f[v-c[i]]+w[i]}计算出结果。
4、循环结束后,判断f[sum/2]是否等于sum/2,是的话返回true,否则返回false。
算法复杂度:整个函数只用了两层循环解决问题,所以最坏复杂度为O(NV),其中N是数组大小,V是数组总和的一半。
代码如下:
class Solution {
public:
bool canPartition(vector<int>&nums) {
int n=nums.size();
if(n==0)return true;
if(n==1)return false;
int sum=0;
for(int i=0;i<n;i++){
sum+=nums[i];
}
if(sum%2==1)
return false;
vector<int> t(sum/2+1,0);
//vector<vector<int> >t(n+1,temp);
for(int i=1;i<=n;i++){
for(int j=sum/2;j>=0;j--){
if(j>=nums[i-1])
t[j]=max(t[j],t[j-nums[i-1]]+nums[i-1]);
}
}
return t[sum/2]==sum/2;
}
};