📌  相关文章
📜  给定数组表示S所需的最小数目的数字(1)

📅  最后修改于: 2023-12-03 15:11:40.461000             🧑  作者: Mango

给定数组表示S所需的最小数目的数字

问题描述

给定一个由数字组成的数组和一个目标数字S,现在需要从数组中选出一些数字,并使它们的和等于S。如果可以找到这样的数字,输出需要选出的数字的最小个数,否则输出-1。

例如:给定数组[2,3,1,4,2]和目标数字S为7,需要从数组中选出数字2、3、2使它们的和等于7,因此输出3。

算法分析

这个问题可以通过动态规划来解决。具体来说,我们可以定义一个二维数组dp,其中dp[i][j]表示从数组的前i个数字中选出一些数字使它们的和等于j所需的最小数字个数。显然,当j=0时,我们可以选择不选任何数字,因此dp[i][0]=0;当i=0时,因为数组为空,不可能选出任何数字,因此dp[0][j]=无穷大。

对于每个数字nums[i],我们有两个选择:选它或不选它。如果我们选择不选它,那么dp[i][j]=dp[i-1][j];如果我们选择选它,那么dp[i][j]=dp[i-1][j-nums[i]]+1。我们选取这两种方法中的较小值作为dp[i][j]的值,即

dp[i][j] = min(dp[i-1][j], dp[i-1][j-nums[i]]+1)

最终,当dp[n][S]为无穷大时,说明从数组中无法选出数字使它们的和等于S,输出-1,否则输出dp[n][S]即为需要选出的数字的最小个数。

代码实现
def findMinNum(nums, S):
    n = len(nums)
    dp = [[float('inf') if j > 0 else 0 for j in range(S+1)] for i in range(n+1)]
    for i in range(1, n+1):
        for j in range(1, S+1):
            if nums[i-1] <= j:
                dp[i][j] = min(dp[i-1][j], dp[i-1][j-nums[i-1]]+1)
            else:
                dp[i][j] = dp[i-1][j]
    return dp[n][S] if dp[n][S] != float('inf') else -1
测试样例
  1. 输入:nums=[2,3,1,4,2], S=7;输出:3。

  2. 输入:nums=[1,2,3,4,5], S=10;输出:2。

  3. 输入:nums=[1,1,1,1,1], S=6;输出:6。

时间复杂度

由于在二维数组dp中,我们需要计算dp[i][j]的值时都需要遍历前面所有的数字,因此总时间复杂度为O(nS)。