494. Target Sum -Medium

本文介绍了一种利用动态规划解决符号分配问题的方法。给定一个非负整数列表及目标值S,通过分配+或-符号使得列表中整数之和等于S,求解可能的分配方式数量。以实例[1,1,1,1,1]与目标3为例,详细阐述了解题思路及算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Question

You are given a list of non-negative integers, a1, a2, …, an, and a target, S. Now you have 2 symbols + and -. For each integer, you should choose one from + and - as its new symbol.

Find out how many ways to assign symbols to make sum of integers equal to target S.

给你一个包含非负整数的列表以及一个目标S。现在你有两个运算符+和-。对每个整数,你可以选择+或-。找出有多少种方法去使这些整数的总和达到S

Example

Input: nums is [1, 1, 1, 1, 1], S is 3.
Output: 5
Explanation:

-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

There are 5 ways to assign symbols to make the sum of nums be target 3.

Solution

  • 动态规划解。因为一部分数字我们赋予+,一部分赋予-,所以我们把赋予+的集合称为P,赋予-的集合称为N。

    引自leetcode
    sum(P) - sum(N) = target
    sum(P) + sum(N) + sum(P) - sum(N) = target + sum(P) + sum(N)
    2 sum(P) = target + sum(nums)*

    所以问题就转化成了如何把使列表的总和达到(target + sum(nums)) / 2(当然要求是target + sum(nums)一定为偶数)。定义dp[i]: 列表总和达到i的方法数。因为这里每个元素只能计算一次,所以每次新加入一个n,更新dp[n:target]。(而不是直接从dp[0]更新到dp[target],这种方法适合每个元素允许多次计算)。递推式: dp[i] += dp[t - i] (i<=t<=target)

    class Solution(object):
        def findTargetSumWays(self, nums, S):
            """
            :type nums: List[int]
            :type S: int
            :rtype: int
            """
            # 如果nums所有加起来都达不到S或者 target 不是偶数 (sum(nums) + S)
            if (sum(nums) + S) % 2 != 0 or S > sum(nums): return 0
            # 只要计算nums中的元素总和加到target即可
            target = int((sum(nums) + S) / 2)
            dp = [1] + [0] * target
            # 因为nums中的每个元素只能使用一次,所以计算每加入一个n,更新dp[n:target]
            for n in nums:
                # 一定要从target更新到n,否则会出现重复增加
                for t in range(target, n - 1, -1):
                    dp[t] += dp[t - n]  # 每出现一个n,都加上总和为t-n时的方法数(因为能够到达t-n,也肯定能到达t)
            return dp[-1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值