算法: 求和377. Combination Sum IV

本文介绍了如何使用动态规划解决组合求和问题,即给定一个不重复的整数数组和一个目标值,计算所有可能的组合方式。通过自底向上的DP方法,从较小的和开始逐步构建到目标值,避免了重复计算。示例展示了如何应用这个算法,并给出了Python实现。

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

377. Combination Sum IV

Given an array of distinct integers nums and a target integer target, return the number of possible combinations that add up to target.

The test cases are generated so that the answer can fit in a 32-bit integer.

Example 1:

Input: nums = [1,2,3], target = 4
Output: 7
Explanation:
The possible combination ways are:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)

Note that different sequences are counted as different combinations.
Example 2:

Input: nums = [9], target = 3
Output: 0

Constraints:

  • 1 <= nums.length <= 200
  • 1 <= nums[i] <= 1000
  • All the elements of nums are unique.
  • 1 <= target <= 1000

Follow up: What if negative numbers are allowed in the given array? How does it change the problem? What limitation we need to add to the question to allow negative numbers?

从下到上求解

说明:以问题中的示例为例,其中 nums 为 [1, 2, 3],目标为 4。以下是您如何自下而上构建解决方案的方法,首先是总和为 1,然后是数字您总共可以制作 2 种方法,依此类推,最多 4 种:

1 -> [1]
2 -> [1, 1], [2]
3 -> [1, 1, 1], [1, 2], [2, 1], [3]
4 -> [1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1]

由于我们只需要计数,而不是实际的组合,因此可以将其简化为以下 DP 算法:

前置步骤:将 DP 数组初始化为 nums 中的每个数字的 1(因为您可以通过仅使用该数字本身轻松地得出该总数),否则为 0。

DP = [0, 1, 1, 1, 0]

现在,对于通往目标的每个数字,调用该子目标t_sub。通过获取 nums 中的每个数字n并检查我们能够制作 t_sub - n 的方式,然后将 其添加到t_sub的 DP 条目,看看我们可以通过多少种方式制作t_sub。

第 1 步:

t_sub = 1
t_sub - 1 = 0 所以什么都不加
t_sub - 2 < 0 所以什么都不加
t_sub - 3 < 0 所以什么都不加
DP = [0, 1, 1, 1, 0]

第 2 步:

t_sub = 2
t_sub - 1 = 1 所以 DP[2] += DP[1] 现在是 2
t_sub - 2 = 0 所以什么都不加
t_sub - 3 < 0 所以什么都不加
DP = [0, 1, 2 , 1, 0]

第 3 步:

t_sub = 3
t_sub - 1 = 2 所以 DP[3] += DP[2] 现在是 3
t_sub - 2 = 1 所以 DP[3] += DP[1] 现在是 4
t_sub - 3 = 0 所以什么都不加
DP = [0, 1, 2, 4, 0]

第 4 步:

t_sub = 4
t_sub - 1 = 3 所以 DP[4] += DP[3] 现在是 4
t_sub - 2 = 2 所以 DP[4] += DP[2] 现在是 6
t_sub - 3 = 1 所以 DP[4] += DP[1] 现在是 7
DP = [0, 1, 2, 4, 7]

现在我们完成了,所以返回 DP[-1],这是当t_sub是目标时我们可以制作t_sub的方式数。

在我们构建dp时,对于i的每个值,我们将遍历数字数组 ( N ) 中的不同num ,并通过添加来更新每个 num ( dp[i+num] )可以到达的单元格的值当前单元格的结果(dp[i])。如果当前单元格没有值,那么我们可以继续而不需要遍历N。

我们需要将dp[0]的值设为1来表示共同起点的值,然后一旦迭代完成,我们就可以返回 dp[T]作为我们的最终答案。

在自顶向下和自底向上的 DP 解决方案中,时间复杂度为O(N * T),空间复杂度为O(T)。

class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        nums, combs = sorted(nums), [1] + [0] * (target)
        for i in range(target + 1):
            for num in nums:
                if num  > i: break
                if num == i: combs[i] += 1
                if num  < i: combs[i] += combs[i - num]
        return combs[target]
class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        dp = [0] * (target + 1)
        dp[0] = 1
        for i in range(1, target+1):
            for n in nums:
                if n <= i:
                    dp[i] += dp[i-n]
        return dp[-1]

参考

https://leetcode.com/problems/combination-sum-iv/discuss/294990/Python-DP-beats-97-speed-and-91-memory-(with-explanation)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值