416. Partition Equal Subset Sum

问题:

给定一组数,请问是否将其分为两个数组,使得二者和相等。

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.

  

解法:DP(动态规划) 0-1 knapsack problem(0-1背包问题)

1.确定【状态】:

  • 可选择的数:前 i 个数
  • 和:s:0~全元素和/2

2.确定【选择】:

  • 选择当前的数nums[i]
  • 不选择当前的数nums[i]

3. dp[i][s]的含义:

前 i 个数中,组成和=s 的可能是否存在。

4. 状态转移:

dp[i][s]= OR {

  • 选择 nums[i]:dp[i-1][s-nums[i]]:=前 i-1 个元素可组成和为 s-nums[i] 的可能性
  • 不选择 nums[i]:dp[i-1][s]:=前 i-1 个元素可组成和为 s 的可能性

}

5. base case:

  • dp[0][s]=false
  • dp[i][0]=true
  • dp[0][0]=true

代码参考:

 1 class Solution {
 2 public:
 3     //dp[i][s]: in first i items, sum is s, exists?
 4     //case_1,choose i-th item: dp[i-1][s-val[i]]
 5     //case_2,don't choose: dp[i-1][s]
 6     //dp[i][s] = case_1 OR case_2
 7     //base case: dp[0][s] = false
 8     //dp[i][0] = true
 9     //dp[0][0] = true
10     bool canPartition(vector<int>& nums) {
11         bool res;
12         int sum = 0;
13         for(int n:nums){
14             sum+=n;
15         }
16         if(sum%2) return false;
17         sum/=2;
18         vector<vector<bool>> dp(nums.size()+1, vector<bool>(sum+1, false));
19         dp[0][0] = true;
20         for(int i = 1; i<=nums.size(); i++) {
21             for(int s = 1; s<=sum; s++) {
22                 if(s-nums[i-1]<0) dp[i][s] = dp[i-1][s];
23                 else dp[i][s] = dp[i-1][s-nums[i-1]] || dp[i-1][s];
24             }
25         }
26         return dp[nums.size()][sum];
27     }
28 };

 

♻️ 优化:空间复杂度:2维->1维

去掉 i 

将 s 倒序遍历。

if(s-nums[i-1]<0) dp[i][s] = dp[i-1][s];
else dp[i][s] = dp[i-1][s-nums[i-1]] || dp[i-1][s];

上述状态转移中,i 代表行,s 代表列

则都为 更新本行 : 使用上一行的 本列前面的列 来计算覆盖本列

顺序遍历的话,更新后面列的时候,会用到已经被覆盖掉的本列。而我们期望用的是上一行的本列

因此 将 s 倒序遍历。更新前面的列,用的上一行本列,还未被本行操作更新。

 

代码参考:

 1 class Solution {
 2 public:
 3     //dp[i][s]: in first i items, sum is s, exists?
 4     //case_1,choose i-th item: dp[i-1][s-val[i]]
 5     //case_2,don't choose: dp[i-1][s]
 6     //dp[i][s] = case_1 OR case_2
 7     //base case: dp[0][s] = false
 8     //dp[i][0] = true
 9     //dp[0][0] = true
10     bool canPartition(vector<int>& nums) {
11         bool res;
12         int sum = 0;
13         for(int n:nums){
14             sum+=n;
15         }
16         if(sum%2) return false;
17         sum/=2;
18         vector<bool> dp(sum+1, false);
19         dp[0] = true;
20         for(int i = 1; i<=nums.size(); i++) {
21             for(int s = sum; s>0; s--) {
22                 if(s-nums[i-1]>=0) {
23                     dp[s] = dp[s-nums[i-1]] || dp[s];
24                 }
25             }
26         }
27         return dp[sum];
28     }
29 };

 

posted @ 2020-08-29 12:06  habibah_chang  阅读(128)  评论(0编辑  收藏  举报