題目
You are given a list of non-negative integers, a1, a2, …, an, and a target, S. Now you have 2 symbols + and -. For each integer, you should choose one from + and – as its new symbol.
Find out how many ways to assign symbols to make sum of integers equal to target S.
題目會傳入兩個參數 nums (數字陣列)、S (整數),限制只能使用兩個運算符號 +、- 改變數字陣列 nums 的數字讓總和等於 S
解題過程
我自己比較少接觸演算法的東西(大學沒學好),就算去翻解答也看不懂別人在寫什麼東西,後來看了 演算法筆記- Backtracking 的圖解後終於理解解答再寫什麼東西
答案
回溯法:
static int FindTargetSumWays(int[] nums, int S)
{
int sum = nums.Sum();
return Calculate(nums, 0, S, sum);
}
static int Calculate(int[] nums, int idx, int targetSum, int sum)
{
if (idx == nums.Length)
{
return (targetSum == 0) ? 1 : 0;
}
// 數字加總 如果小於 目標加總 就不用跑後面的列舉
else if (sum < targetSum)
{
return 0;
}
int nextIdx = idx + 1;
return Calculate(nums, nextIdx, targetSum + nums[idx], sum) +
Calculate(nums, nextIdx, targetSum - nums[idx], sum);
}
回溯法+暫存:
static int FindTargetSumWays2(int[] nums, int S)
{
int sum = nums.Sum();
// 利用快取的方式減少重複運算
int[][] cache = new int[nums.Length][];
for (int i = 0; i < cache.Length; i++)
{
cache[i] = new int[(2 * sum) + 1];
Array.Fill(cache[i], -1);
}
return Calculate2(nums, 0, S, sum, cache);
}
static int Calculate2(int[] nums, int idx, int targetSum, int sum, int[][] cache)
{
if (idx == nums.Length)
{
return (targetSum == 0) ? 1 : 0;
}
// 數字加總 如果小於 目標加總 就不用跑後面的列舉
else if (sum < targetSum)
{
return 0;
}
int nextIdx = idx + 1;
if (cache[idx][sum + targetSum] < 0)
{
cache[idx][sum + targetSum] =
Calculate2(nums, nextIdx, targetSum + nums[idx], sum, cache) +
Calculate2(nums, nextIdx, targetSum - nums[idx], sum, cache);
}
return cache[idx][sum + targetSum];
}
原始碼:GitHub