【问题标题】:Find all combinations of a list of numbers with a given sum查找具有给定总和的数字列表的所有组合
【发布时间】:2016-04-03 17:17:42
【问题描述】:

我有一个数字列表,例如

numbers = [1, 2, 3, 7, 7, 9, 10]

如您所见,数字可能在此列表中出现多次。

我需要得到这些数字的所有组合,它们具有给定的总和,例如10

组合中的项目可能不会重复,但 numbers 中的每个项目都必须被唯一处理,这意味着例如列表中的两个7 代表具有相同值的不同项目。

顺序不重要,所以[1, 9][9, 1] 是相同的组合。

组合没有长度限制,[10][1, 2, 7] 一样有效。

如何创建符合上述条件的所有组合的列表?

在这个例子中,它是[[1,2,7], [1,2,7], [1,9], [3,7], [3,7], [10]]

【问题讨论】:

    标签: python algorithm python-3.x combinations subset-sum


    【解决方案1】:

    您可以使用 itertools 遍历每个可能大小的每个组合,并过滤掉所有不等于 10 的内容:

    import itertools
    
    numbers = [1, 2, 3, 7, 7, 9, 10]
    target = 10
    
    result = [seq for i in range(len(numbers), 0, -1)
              for seq in itertools.combinations(numbers, i)
              if sum(seq) == target]
    
    print(result)
    

    结果:

    [(1, 2, 7), (1, 2, 7), (1, 9), (3, 7), (3, 7), (10,)]
    

    不幸的是,这有点像 O(2^N) 复杂度,因此它不适合大于 20 个元素的输入列表。

    【讨论】:

    • 如果你对上面的代码有疑惑,这里是上面代码的简单版本 for i in range(1,len(a)): for s in itertools.combinations(a,i) : 如果 sum(s)==sum1: print(s)
    • 这段代码有时间复杂度更小的版本吗?
    • @Kevin : 如何处理更多元素?
    • itertools.combinations 将在numbers 有重复元素时创建重复元素。
    【解决方案2】:

    solution @kgoodrick offered 很棒,但我认为它作为生成器更有用:

    def subset_sum(numbers, target, partial=[], partial_sum=0):
        if partial_sum == target:
            yield partial
        if partial_sum >= target:
            return
        for i, n in enumerate(numbers):
            remaining = numbers[i + 1:]
            yield from subset_sum(remaining, target, partial + [n], partial_sum + n)
    

    list(subset_sum([1, 2, 3, 7, 7, 9, 10], 10)) 产生[[1, 2, 7], [1, 2, 7], [1, 9], [3, 7], [3, 7], [10]]

    【讨论】:

    • 你能解释一下“yield from subset_sum(remaining, target, partial + [n], partial_sum + n)”这一行吗
    • @Martin Valgur:它可以处理 10000 个列表元素吗?
    • 如果列表中的元素不完全不同,这将创建重复项。
    【解决方案3】:

    之前有人问过这个问题,请参阅 @msalvadores 回答 here。我更新了在 python 3 中运行的 python 代码:

    def subset_sum(numbers, target, partial=[]):
        s = sum(partial)
    
        # check if the partial sum is equals to target
        if s == target:
            print("sum(%s)=%s" % (partial, target))
        if s >= target:
            return  # if we reach the number why bother to continue
    
        for i in range(len(numbers)):
            n = numbers[i]
            remaining = numbers[i + 1:]
            subset_sum(remaining, target, partial + [n])
    
    
    if __name__ == "__main__":
        subset_sum([3, 3, 9, 8, 4, 5, 7, 10], 15)
    
        # Outputs:
        # sum([3, 8, 4])=15
        # sum([3, 5, 7])=15
        # sum([8, 7])=15
        # sum([5, 10])=15
    

    【讨论】:

    • 如果您希望每个输出包含一定数量的数字 - 比如 12。每个列表需要有 12 个数字并且总和为 15?
    • @max 我正在寻找与您类似的解决方案,您找到了吗?
    • @qasimalbaqali 我做到了。不要介意我的 cmets,但这有效:# Python3 程序在具有给定总和的整数列表中查找所有对 from itertools import combination def findPairs(lst, K, N): return [pair for pair in combination(lst, N) if sum(pair) == K] #monthly cost range;唯一数字 lst = list(range(10, 30)) #每台机器/客户的年收入总和 K = 200 #月数(12 - 9 = 免费月数) N = 9 print('可能的每月订阅费用仍然相当于每年 200 美元:') #print(findPairs(lst, K, N)) findPairs(lst,K,N)
    【解决方案4】:

    @qasimalbaqali

    这可能不是帖子所要查找的内容,但如果您愿意:

    找出一系列数字 [lst] 的所有组合,其中每个 lst 包含 N 个元素,并且总和为 K:使用此:

    # Python3 program to find all pairs in a list of integers with given sum  
    from itertools import combinations 
    
    def findPairs(lst, K, N): 
        return [pair for pair in combinations(lst, N) if sum(pair) == K] 
    
    #monthly cost range; unique numbers
    lst = list(range(10, 30))
    #sum of annual revenue per machine/customer
    K = 200
    #number of months (12 - 9 = num months free)
    N = 9
    
    print('Possible monthly subscription costs that still equate to $200 per year:')
    #print(findPairs(lst, K, N)) 
    findPairs(lst,K,N)
    

    结果:

    Possible monthly subscription costs that still equate to $200 per year:
    Out[27]:
    [(10, 11, 20, 24, 25, 26, 27, 28, 29),
     (10, 11, 21, 23, 25, 26, 27, 28, 29),
     (10, 11, 22, 23, 24, 26, 27, 28, 29),
    

    这背后的想法/问题是“如果我们免费提供 x 个月并且仍然达到收入目标,我们每个月可以收取多少费用”。

    【讨论】:

      【解决方案5】:

      这行得通...

      from itertools import combinations
      
      
      def SumTheList(thelist, target):
          arr = []
          p = []    
          if len(thelist) > 0:
              for r in range(0,len(thelist)+1):        
                  arr += list(combinations(thelist, r))
      
              for item in arr:        
                  if sum(item) == target:
                      p.append(item)
      
          return p
      

      【讨论】:

        猜你喜欢
        • 2022-06-14
        • 1970-01-01
        • 2017-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多