题目
给定一个非负整数数组,a1,a2, … , an,和一个目标数,S。现在你有两个符号+ 和 -。对于数组中任意一个整数,你都可以从 + 和 - 中选择一个符号添加在前面。
返回可以使最终数组和为目标数S的所有添加符号的方法数。
思路
思路一:深度优先搜索策略(回溯法)
class Solution:
result = 0
def findTargetSumWays(self, nums: List[int], S: int) -> int:
if len(nums) == 0: return 0
self.backtrack(nums, i = 0, S)# i表示第i个元素
return self.result
# 回溯法模板
def backtrack(self, nums, i, rest):
# i表示第i个元素
# base case
if i == len(nums):
if rest == 0:
self.result += 1
return
# 给nums[i]选择 - 号
rest += nums[i]
# 穷举 nums[i + 1]
self.backtrack(nums, i +1, rest)
# 撤销选择
rest -= nums[i]
# 给nums[i] 选择 + 号
rest -= nums[i]
self.backtrack(nums, i + 1, rest)
rest += nums[i]
复杂度分析
- 时间复杂度:O(2^N),其中 NN 是数组
nums
的长度。 - 空间复杂度:O(N),为递归使用的栈空间大小。
更优雅的实现
class Solution:
count = 0
def findTargetSumWays(self, nums: List[int], S: int) -> int:
self.calculate(nums, 0, 0, S)
return self.count
def calculate(self, nums, i, Sum, target):
if i == len(nums):
if Sum == target:
self.count += 1
else:
self.calculate(nums, i + 1, Sum + nums[i], target)
self.calculate(nums, i + 1, Sum - nums[i], target)
思路二:动态规划
还没搞懂
系统学了动态规划再看
这道题是一道常见的背包问题。
状态变量:dp[i][j]:数组中前i个元素,组成和为j的方案数。
转移方程:
dp[i][j] = dp[i - 1][j - nums[i]] + dp[i - 1][j + nums[i]]
class Solution:
def findTargetSumWays(self, nums: List[int], S: int) -> int:
if not nums: return 0
dp = [0] * (target + 1)
dp[0] = 1 # 凑够目标i一共有dp[i]中方法
for i in range(1, target + 1):
for num in nums:
if i >= num:
dp[i] += dp[i - num]
return dp[target]
- todo
https://leetcode-cn.com/problems/target-sum/solution/python-dfs-xiang-jie-by-jimmy00745/
class Solution:
def findTargetSumWays(self, nums: List[int], S: int) -> int:
if sum(nums) < S or (sum(nums) + S) % 2 == 1: return 0
P = (sum(nums) + S) // 2
dp = [1] + [0 for _ in range(P)]
for num in nums:
for j in range(P,num-1,-1):
dp[j] += dp[j - num]
return dp[P]