###### tags: `Leetcode` `medium` `dynamic programming` `python` `c++` # 494. Target Sum ## [題目連結:] https://leetcode.com/problems/target-sum/description/ ## 題目: You are given an integer array ```nums``` and an integer ```target```. You want to build an **expression** out of nums by adding one of the symbols ```'+'``` and ```'-'``` before each integer in nums and then concatenate all the integers. * For example, if ```nums = [2, 1]```, you can add a ```'+'``` before ```2``` and a ```'-'``` before ```1``` and concatenate them to build the expression ```"+2-1"```. Return the number of different **expressions** that you can build, which evaluates to ```target```. **Example 1:** ``` Input: nums = [1,1,1,1,1], target = 3 Output: 5 Explanation: There are 5 ways to assign symbols to make the sum of nums be target 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 +1 + 1 + 1 + 1 - 1 = 3 ``` **Example 2:** ``` Input: nums = [1], target = 1 Output: 1 ``` ## 解題想法: * 給定一個數組與一個target number,對於此數組每個數天加'+'、'-',使其求和為target number,求滿足的組合數 * 使用DP: * 定義dp[i][j]: **到第i個數和為j的組合數** * (nums: 0~i-1,第i個數字為nums[i-1]) * dp[i][j]=case1+case2: * **Case1:** * **dp[i-1][j-nums[i-1]]** * 使用前i-1個數字,可構成j-nums[i-1] * 則加上nums[i-1] (+第i個數字)即可為j * **Case2:** * **dp[i-1][j+nums[i-1]]** * 使用前i-1個數字,可構成j+nums[i-1] * 則減掉nums[i] (-第i個數字)即可為j * 對於初始dp: * max_sum=sum(nums) * **dp=[[0 for _ in range(2*max_sum+1)] for _ in range(len(nums)+1)]** * 因為範圍可以為(-max_sum)至(+max_sum) * 所以取0~ 2 * max_sum+1 * 初始 * dp[0][0]=1: 使用0個數總和為0,1種組合 * pos_0=max_sum: **總和為0的位置在中間** ## Python: ``` python= class Solution(object): def findTargetSumWays(self, nums, target): """ :type nums: List[int] :type target: int :rtype: int """ #dp[i][j]:到第i個數(nums: 0~i-1,第i個數字為nums[i-1]) 和為j的組合數 max_sum=sum(nums) if max_sum<target: return 0 #dp m:len(nums)+1 n:位置從-max_sum~0~+max_sum dp=[[0 for _ in range(2*max_sum+1)] for _ in range(len(nums)+1)] pos_0=max_sum #和為0的位置在中間 dp[0][pos_0]=1 #初始: 用0個數和為0 總共一種 for i in range(1, len(nums)+1): for j in range(2*max_sum+1): #使用前i-1個數字 可構成j+nums[i-1]: 則-nums[i](-第i個數字)即可為j dp[i][j]+=dp[i-1][j+nums[i-1]] if j+nums[i-1]<2*max_sum+1 else 0 #使用前i-1個數字 可構成j-nums[i-1]: 則+nums[i-1](+第i個數字)即可為j dp[i][j]+=dp[i-1][j-nums[i-1]] if j-nums[i-1]>=0 else 0 return dp[len(nums)][target+pos_0] ``` * 上述缺點為浪費記憶體空間 * ex: nums=[100], targert=200 * dp要準備200個空間太浪費了 * 可以用hash table存 * 或者改用dfs遍歷而非dp (網路大神蠻多dfs解的~但尚未研究) ## C++: * 二維陣列可以用**vector<unordered_map<int, int>>** * dp[i][j]=value ``` cpp= class Solution { public: int findTargetSumWays(vector<int>& nums, int target) { int n=nums.size(); vector<unordered_map<int, int>> dp(n+1); dp[0][0]=1; for (int i=1; i<n+1; i++){ //當前要求dp[i],需要由dp[i-1]往推算 for (auto &j: dp[i-1]){ int curSum=j.first, count=j.second; dp[i][curSum-nums[i-1]]+=count; dp[i][curSum+nums[i-1]]+=count; } } return dp[n][target]; } }; ```