1.题目描述
给定一个非负整数数组,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位整数存下。
2.解题思路
方案一:dfs+剪枝
里先给出用DFS+记忆化+剪枝的方法:
直接使用DFS会超时,要做一些优化,使用dp字典来记录在遍历到第i个元素和为sum(即,字典键为(i,sum))时,满足数组所有数值和为S的个数(即,字典值为cnt)。
假设nums中有4个数,target =2,返回4
在每一行中,假设目标值曾经出现过,那就不用再算了,比如说橘黄色的第二个0出现时,由于之前0出现过,这个就不用再分解了,因为后续是重复的操作
方案二:动态规划
思路后续会给出
3.代码实现
方案一:
class Solution(object):
def findTargetSumWays(self, nums, S):
"""
:type nums: List[int]
:type S: int
:rtype: int
"""
if not nums:
return 0
dp = {}
res = self.helper(nums, S, 0, 0, dp)
return res
def helper(self, nums, S, i, sum, dp):
if i == len(nums):
return S == sum
if i < len(nums) and (i, sum) in dp:
return dp.get((i, sum))
if i < len(nums) and (i, sum) not in dp:
cnt1 = self.helper(nums, S, i+1, sum+nums[i], dp)
cnt2 = self.helper(nums, S, i+1, sum-nums[i], dp)
dp[(i, sum)] = cnt1 + cnt2
return dp.get((i, sum))
方案二:后续给出