【发布时间】:2021-01-09 05:00:49
【问题描述】:
问题描述如下 https://leetcode.com/problems/target-sum/
给定一个非负整数列表 a1、a2、...、an 和一个目标 S。现在您有 2 个符号 + 和 -。对于每个整数,您应该从 + 和 - 中选择一个作为其新符号。
找出有多少种分配符号的方法以使整数之和等于目标 S。
约束:
- 给定数组的长度为正数,不会超过 20。
- 给定数组中元素的总和不会超过 1000。
- 保证您的输出答案适合 32 位整数。
我在 leetcode 提交详情 Accepted Solutions Runtime Distribution 中找到了这个提交
class Solution:
def findTargetSumWays(self, nums, S):
a = sum(nums) - S
if a < 0 or a%2==1: return 0
S = [((1<<(i*21))+1) for i in nums]
return reduce(lambda p,i:(p*i)&(1<<((a//2+1)*21))-1,S,1)>>(21*a//2)
简化reduce,就变成了
class Solution:
def findTargetSumWays(self, nums, S):
a = sum(nums) - S
if a < 0 or a%2==1: return 0
auxarr = [((1<<(i*21))+1) for i in nums]
ret=1
for i in auxarr:
ret= (ret*i)&(1<<((a//2+1)*21))-1
return ret>>(21*a//2)
它将原始问题转换为另一个问题,即找到选择一些nums[i]且它们的总和为(sum(nums)-S)/2的选择数。
我知道如何用dp解决这样的背包问题,但是我看不懂上面的代码,我很好奇这样的代码是如何工作的,请帮助我。
# my dp code
class Solution:
def findTargetSumWays(self, nums: List[int], S: int) -> int:
S=sum(nums)-S
if S%2!=0 or S<0: return 0
S//=2
dp=[0]*(S+1)
dp[0]=1
for c in nums:
for j in range(S,c-1,-1):
dp[j]+=dp[j-c]
return dp[S]
【问题讨论】:
-
您可以将
ret和auxarr的元素视为0 和1 的列表。((1<<(i*21))+1)将对应一个列表,其中位置 0 和 i*21 的元素为 1,其余为 0 -
或者更好地作为 [0, 2^21) 范围内的整数列表而不是位
标签: python