【LeetCode-揹包】目標和
阿新 • • 發佈:2020-08-27
題目描述
給定一個非負整數陣列,a1, a2, ..., an, 和一個目標數,S。現在你有兩個符號 + 和 -。對於陣列中的任意一個整數,你都可以從 + 或 -中選擇一個符號新增在前面。
返回可以使最終陣列和為目標數 S 的所有新增符號的方法數。
示例:
輸入:nums: [1, 1, 1, 1, 1], S: 3
輸出:5
解釋:
-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3
一共有5種方法讓最終目標和為3。
說明:
- 陣列非空,且長度不會超過 20 。
- 初始的陣列的和不會超過 1000 。
- 保證返回的最終結果能被 32 位整數存下。
題目連結: https://leetcode-cn.com/problems/target-sum/
思路
假設我們將陣列分為兩部分,兩部分的和分別為 x,y,陣列中所有元素的和為 sum,則有 x + y = sum, x - y = S,可得 x = (sum + S) / 2. 所以,問題就變為了陣列能否分為兩部分,其中一部分的和為 (sum + S) / 2。可以使用和等和子集一樣的方法來做。
- 狀態定義:dp[i][j] 表示下標範圍為 [0, i] 內陣列元素中和為 j 的個數;
- 狀態轉移:對於第 i 個數,可以選也可以不選,所以 dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i]];
- 邊界條件:dp[i][0] = 1,含義是範圍 [0, i] 內元素和為 0 的個數為 1,也就是所有的數都不選;dp[0][nums[0]] += 1 if nums[0]<=x,本來 dp[0][0] = 1,如果 nums[0] = 0,此時 dp[0][0] 就等於 2 了,也就可以選擇 nums[0],也可以不選擇 nums[0],因為 nums[0] = 0,所以這兩種方法是一樣的。
程式碼如下:
class Solution { public: int findTargetSumWays(vector<int>& nums, int S) { if(nums.empty() && S>0) return 0; int s = 0; for(int i=0; i<nums.size(); i++){ s += nums[i]; } if(s<S) return 0; s += S; if(s%2!=0) return 0; int target = s / 2; vector<vector<int>> dp(nums.size(), vector<int>(target+1, 0)); for(int i=0; i<nums.size(); i++) dp[i][0] = 1; // 邊界條件 /*if(nums[0]<=target) dp[0][nums[0]] = 1; if(nums[0]==0) dp[0][nums[0]] = 2;*/ if(nums[0]<=target) dp[0][nums[0]] += 1; // 這種寫法和上面註釋的寫法是一樣的 for(int i=1; i<nums.size(); i++){ for(int j=0; j<=target; j++){ dp[i][j] = dp[i-1][j]; if(j>=nums[i]){ dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i]]; } } } return dp[nums.size()-1][target]; } };
空間複雜度優化:
使用和等和子集一樣的方法對空間複雜度進行優化:
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
if(nums.empty() && S>0) return 0;
int s = 0;
for(int i=0; i<nums.size(); i++){
s += nums[i];
}
if(s<S) return 0;
s += S;
if(s%2!=0) return 0;
int target = s / 2;
vector<int> dp(target+1, 0);
dp[0] = 1;
if(nums[0]<=target) dp[nums[0]] += 1;
for(int i=1; i<nums.size(); i++){
for(int j=target; j>=nums[i]; j--){
dp[j] += dp[j-nums[i]];
}
}
return dp[target];
}
};