先考虑对称性,如果把示例的正负号颠倒一下,就是-3了,所以target只要是大于等于0的即可,先取个绝对值简化计算。
因此很容易想到特殊情况一:如果所有数字只和S都比target小,那返回0.
我们将前面带正号的数字和为Sp,带符号的为Sq,那么
S=Sp+Sq
并且
Sp-Sq=target
因此得到
Sq=(S-target)/2
我们知道要计算的数字都是整数,因此得到特殊情况2:(S-target)/2非正整数的返回0,也就是(S-target)%2==1的情况。
现在问题转化成Sq=(S-target)/2这个表达式,也就是”选出一组数字,能够和为Sq的情况有多少种"
转化成了01背包问题——每个数字都有选或者不选的情况,但是要装满容量为Sq的包。
如果用数组表示那如果原来的数字集合为[1,2]
那么dp=[1,1,1]表示空包1中方法,和为1一种方法,和为2也是一种方法。
如果加入考虑数字1,数字集合变成[1,2,1]
那么dp=[1,2,2,],因为dp[i]+=dp[i-n],也就是经由和为i-n的组合加上n就可以得到i,那么dp[i-n]表示的方法数就可以被加过来。
class Solution:
def findTargetSumWays(self, nums: List[int], target: int) -> int:
s=sum(nums)
target=abs(target)
if s<target or (s-target)%2!=0:
return 0
target=(s-target)//2
dp=[0]*(target+1)
dp[0]=1
for n in nums:
for i in range(target,n-1,-1):
dp[i]+=dp[i-n]
return dp[-1]