先給出一個遞歸的解法。主要思想:一組數,每個數會有 + 和 - 兩種選擇,那我們可以利用遞歸來遍歷求解所有的情況,n個數,就有2^n種情況,實際上是一個二叉樹,每個節點有兩種選擇。實現起來很簡單,但是效率比較差,畢竟有些情況明顯不可取,還是要遍歷。
class Solution {
public:
int count;
int findTargetSumWays(vector<int>& nums, int S) {
count = 0;
f(nums, 0, 0, S);
return count;
}
void f(vector<int>& nums, int index, int sum, int s)
{
if(index == nums.size()){
if(sum == s)count++;
}
else {
f(nums, index + 1, sum + nums[index], s);
f(nums, index + 1, sum - nums[index], s);
}
}
};
下面是動態規劃的方法。
第一種思路,通過某種奇妙的運算,把問題轉化成:求數組中取數,使和爲(target + 數組的和)/ 2 的方案數。
這就變成416這道題。代碼如下:
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
int target = 0;
for(int i = 0; i < nums.size(); i++)
target += nums[i];
if((target + S)%2 == 1 || target < S)return 0;
target = (target + S) >> 1;
int d[target + 1] = {0};
d[0] = 1;
for (int i = 0; i < nums.size(); ++i)
{
for (int j = target; j >= nums[i]; --j){
d[j] += d[j - nums[i]];
}
}
return d[target];
}
};
第二種思想:每個數有加正號和符號兩種選擇,那就類似揹包問題。方程:d[i][j] = d[i - 1][j + num[i - 1]] + d[i-1][j - num[i - 1]]。 表示前i個數添加符號後結果爲j的方案數。需要注意的是,矩陣是比num.size()+1行,S+1列要大