LeetCod:494. Target Sum

LeetCod:494. Target Sum

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.

Example 1:
Input: nums is [1, 1, 1, 1, 1], S is 3. 
Output: 5
Explanation: 

-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

There are 5 ways to assign symbols to make the sum of nums be target 3.
Note:
The length of the given array is positive and will not exceed 20.
The sum of elements in the given array will not exceed 1000.
Your output answer is guaranteed to be fitted in a 32-bit integer.

给定一个数组以及一个目标值,数组中的元素通过加或者减最终得到目标值,求所有可能情况的个数。

思路一:递归

以nums = [1, 1, 1, 1, 1], S = 3. 为例,最终要求的结果是3,数组最后一个元素是1,所以可以分为两种情况:

  1. [1,1,1,1] 的目标值为4,再减1得到3;
  2. [1,1,1,1] 的目标值为2,再加1得到3;
  3. 依次类推,直到只剩最后一个数字的情况。

Python 实现代码

class Solution:
    def findTargetSumWays(self, nums: List[int], S: int) -> int:
        res = self.helper(nums,S)
        return res
    
    def helper(self, nums, S):
        l = len(nums)
        if (l > 1):
            # 越界,无解
            if (abs(S) > sum(nums)):
                res = 0
            else:
                # S+nums[-1]和S-nums[-1]两种情况的结果之和
                res = self.helper(nums[:l-1],S+nums[-1])+self.helper(nums[:l-1],S-nums[-1])
        else:
            # 0特殊对待,有+0和-0结果一样
            if (nums[0] == 0 and S == 0):
                res = 2
            elif (nums[0] == abs(S)):       
                res = 1
            else:
                res = 0
        # print(nums, S, res)
        return res       
思路二:动态规划

问题在于选这个背包或者不选这个背包,而且每个背包只能用一次,所以就是这个背包选还是不选。那么我们就可以映射为:选加号还是选减号。又因为减号不好表示,所以我们将总数往右移。
举个例子【1,1,1,1,1】,表示为-5到5,那我们就直接映射到0到10,变成【2,2,2,2,2】。所以背包容量为10,1表示一个背包的容量为2。
选了一个背包 10 - 2 = 8, 就还剩下8容量的背包。从0开始,值为0的方案数为1,即一个背包都不选【0,0,0,0,0】这种方案。

Python 代码实现

class Solution:
    def findTargetSumWays(self, nums: List[int], S: int) -> int:
        sumAll = sum(nums)
        a = sumAll*2+1
        if(S>=a or S+sumAll>=a):
            return 0
        dp = [0]*a
        
        dp[0] = 1
        for i in range(len(nums)):
            nums[i]=2*nums[i]
        
        for i in range(len(nums)):
            for j in range(nums[i],a)[::-1]:
                dp[j] += dp[j-nums[i]]
            
        return dp[sumAll+S]

注意这里的a = sumAll*2+1,多加了一个1,对应了下面的dp[0] = 1。dp是一个长度为a的数组,每个位置保存对应元素和的情况个数。然后将nums的每个元素乘以2。最后的双重循环就是不断迭代求每个位置元素和的情况个数。核心代码就是里面的dp[j] += dp[j-nums[i]]


THE END.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值