题目:
给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S。现在你有两个符号 +
和 -
。对于数组中的任意一个整数,你都可以从 +
或 -
中选择一个符号添加在前面。
返回可以使最终数组和为目标数 S 的所有添加符号的方法数。
示例 1:
输入: nums: [1, 1, 1, 1, 1], S: 3
输出: 5
解释:
-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
一共有5种方法让最终目标和为3。
注意:
- 数组非空,且长度不会超过20。
- 初始的数组的和不会超过1000。
- 保证返回的最终结果能被32位整数存下。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/target-sum/
解法一:
DFS
只通过递归的方法使用DFS会超出时间限制。
提升方法:
- 使用字典记忆节点(i,sum)时所得解的个数;(主要)
- 先剔除列表中的0,对于每个0,最后解的个数乘以2;
- 当列表的总和小于目标数字S时,无解(列表里的数字都是非负的整数);
- 当列表的总和与目标数字S之差为奇数时无解(添加一个负号,大小变化为偶数)。
class Solution:
def findTargetSumWays(self, nums: List[int], S: int) -> int:
n = 1
l1 = len(nums)
for i in reversed(range(l1)):
if(nums[i] == 0):
del nums[i]
n = n*2
if not nums:
return 2**l1
dp = {}
return n*DFS(nums, S, sum(nums), 0, dp)
def DFS(nums, S, s, i, dp):
if i==len(nums):
if S==0:
return 1
else:
return 0
elif(s<S or (s-S)%2==1):
return 0
else:
if (i,S) not in dp: #如果已经遇到该情况,则跳过求解过程,直接返回结果
a = nums[i]
cnt1 = DFS(nums, S-a, s-a, i+1, dp)
cnt2 = DFS(nums, S+a, s-a, i+1, dp)
dp[(i, S)] = cnt1 + cnt2 #对当前节点求得的解数目进行保存
return dp.get((i, S))