LeetCode416. 分割等和子集

题目

分析

两个子集和相等,转化为找到所有元素总和一半的集合。注意不能回溯,因为时间复杂度为O(2N)会超时。可以将此问题看成0-1背包问题。背包容量为sum / 2。如果总和一半为奇数,那么不可分成两个相同总和的子集。在此问题种物品的重量和价值为数字本身的数值。设dp[i][j]为从0-i中选取不超过容量j 的最大价值。动态转移方程就为01背包的转移方程。每个物品价值为正整数,所以dp数组初始化为0。若有负数,则应初始化为负无穷。

代码

 1 class Solution {
 2 public:
 3     bool canPartition(vector<int>& nums) {
 4         int sum = 0;
 5         for(auto num:nums){
 6             sum += num;
 7         }
 8         if(sum % 2) return false;  //和为奇数必然不能分成两个和相同的子集
 9         sum /= 2;
10         vector<vector<int>> dp(nums.size(),vector<int>(sum+1,0));
11         //int dp[nums.size()][sum+1];
12         //memset(dp,0,sizeof(dp));
13         for(int j = 0;j <= sum;j++){  //初始化
14             if(nums[0] <= j) dp[0][j] = nums[0];
15         }
16           
17         for(int i = 1;i <nums.size();i++){
18             for(int j = 0;j <= sum;j++){
19                 if( j < nums[i]) dp[i][j] = dp[i-1][j];
20                 else dp[i][j] = max(dp[i-1][j],dp[i-1][j-nums[i]] + nums[i]);
21             }
22         }
23         if(sum == dp[nums.size()-1][sum]) return true;
24         else return false;
25     }
26 };

关于二维数组初始化可以memset,也可用vector,10—12行

优化

使用滚动数组将二维转换为一维。dp[i][j] = max(dp[i-1][j],dp[i-1][j-nums[i]] + nums[i])中上一层(i-1层)可以直接拷贝到 i 层上,这样就变成了dp[i][j] = max(dp[i][j],dp[i][j-nums[i]] + nums[i]),就可以把 第一维的 i 去掉,转为一维dp。dp[j]表示容量为j的背包可装的最大价值。动态转移方程:dp[j] = max(dp[j], dp[j - weight[i]] + value[i])。

一维dp需要注意几个问题:

1.遍历顺序:遵从先背包后容量。并且容量要逆序遍历。

解释:不可先容量后背包,先容量后背包这样背包中就只有一个物品。逆序遍历保证每个物品放入一次。

代码

 1 class Solution {
 2 public:
 3     bool canPartition(vector<int>& nums) {
 4         int sum = 0;
 5         for(auto num:nums){
 6             sum += num;
 7         }
 8         if(sum % 2) return false;  //和为奇数必然不能分成两个和相同的子集
 9         sum /= 2;
10         vector<int>dp(sum+1,0);
11           
12         for(int i = 1;i <nums.size();i++){
13             for(int j = sum;j >= nums[i];j--){  //逆序
14                 dp[j] = max(dp[j],dp[j-nums[i]] + nums[i]);
15             }
16         }
17         if(sum == dp[sum]) return true;
18         else return false;
19     }
20 };
原文地址:https://www.cnblogs.com/fresh-coder/p/14400451.html