1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { int ans;
public int findTargetSumWays(int[] nums, int target) { helper(nums, 0, 0, target); return ans; }
private void helper(int[] nums, int pos, int currSum, int target) { if (pos == nums.length) { if (currSum == target) { ans += 1; } return; } helper(nums, pos + 1, currSum + nums[pos], target); helper(nums, pos + 1, currSum - nums[pos], target); } }
|
Backtrack的写法, 把每一种情况都尝试. 一个数字要么是+, 要么是-.
时间复杂度: O(2^n)
空间复杂度: O(n) 用栈.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Solution { private int total;
public int findTargetSumWays(int[] nums, int target) { for (int num : nums) { total += num; } Integer[][] memo = new Integer[nums.length][2 * total + 1]; return calculate(nums, 0, 0, memo, target); }
private int calculate(int[] nums, int pos, int currSum, Integer[][] memo, int target) { if (pos == nums.length) { if (currSum == target) { return 1; } else { return 0; } } if (memo[pos][currSum + total] == null) { int add = calculate(nums, pos + 1, currSum + nums[pos], memo, target); int sub = calculate(nums, pos + 1, currSum - nums[pos], memo, target); memo[pos][currSum + total] = add + sub; } return memo[pos][currSum + total]; } }
|
Recursion with memoization. 存的是在某个pos处, 某个sum被达到的个数. 比如在pos 3, 我想知道从3开始往后的所有combination中能够凑成currSum的个数是多少. 假如有的话, 我就不用再算一遍了, 没有的话我再去算.
memo的列数为2 * total + 1是因为所有组合的范围是[-total, total]共2 * total + 1种情况. 当然其中的某些数字可能凑不到. 但是能到达的范围是这个. 于是我们要想办法把组合成负数的情况给map到某个index. 于是当我们得到某个位置pos能凑到某个currSum的个数时, 我们把它存到memo[pos][currSum + total]的位置. 这样所有情况都有自己的位置. 如果currSum是-total, 那么存到memo[pos][0], 如果是-total + 1, 存到memo[pos][1]…
还有就是当时我在想helper function需要返回东西吗? 答案是需要的. 第47, 48行就解释了. 我们想要知道从某个pos开始能凑到currSum的情况有多少, 这样让helper function返回个东西更方便一些.
那么什么时候存呢? 就是发现memo[pos][currSum]是null的时候, 我们去继续调用helper function, 等+, -两种情况都返回的时候, 我们把这俩得出的答案加在一起存到memo中.
一开始的情况肯定是一路走到最后一个num, 一路上都是加, 然后遇到pos == nums.length, 此时如果是target, 那就返回1, 否则返回0. 然后上一层helper function就能将此时的情况存到memo中, 此时memo[pos][currSum]表示在该pos时, 如果当前累计的sum是currSum, 那么之后的num可以凑成target的情况共有多少种.
时间复杂度: O(t * n) t代表total,
空间复杂度: O(t * n)