416. Partition Equal Subset Sum
阿新 • • 發佈:2020-08-29
問題:
給定一組數,請問是否將其分為兩個陣列,使得二者和相等。
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] = true9 //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 };