查找具有给定总和的数字列表的所有组合

2025-02-20 09:23:00
admin
原创
32
摘要:问题描述:我有一个数字列表,例如numbers = [1, 2, 3, 7, 7, 9, 10] 如您所见,数字可能会在此列表中出现多次。我需要获取这些数字的所有组合,这些数字具有给定的总和,例如10。 组合中的项目不得重复,但其中的每个项目都numbers必须唯一处理,这意味着例如7列表中的两个项目代表具有...

问题描述:

我有一个数字列表,例如

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]]


解决方案 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 个元素的输入列表。

解决方案 2:

这个问题之前已经问过,请参阅@msalvadores 的回答。我更新了给出的 python 代码以在 python 3 中运行:

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

解决方案 3:

@kgoodrick 提供的解决方案很棒,但我认为它作为生成器更有用:

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)

输出:

print(list(subset_sum([1, 2, 3, 7, 7, 9, 10], 10)))
# [[1, 2, 7], [1, 2, 7], [1, 9], [3, 7], [3, 7], [10]]

解决方案 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

解决方案 6:

附加:包括零。

import random as rd

def combine(soma, menor, maior):
    """All combinations of 'n' sticks and '3' plus sinals.
    seq = [menor, menor+1, ..., maior]
    menor = min(seq); maior = max(seq)"""
    lista = []

    while len(set(lista)) < 286: # This number is defined by the combination
                                 # of (sum + #summands - 1, #summands - 1) -> choose(13, 3)     
        zero = rd.randint(menor, maior)

        if zero == soma and (zero, 0, 0, 0) not in lista:
            lista.append((zero, 0, 0, 0))

        else:
            # You can add more summands!

            um = rd.randint(0, soma - zero)
            dois = rd.randint(0, soma - zero - um)
            tres = rd.randint(0, soma - zero - um - dois)


            if (zero + um + dois + tres  == soma and
             (zero, um, dois, tres) not in lista):
                lista.append((zero, um, dois, tres))

    return sorted(lista)
>>> result_sum = 10
>>> combine(result_sum, 0, 10)

输出

[(0,0,0,10), (0,0,1,9), (0,0,2,8), (0,0,3,7), ...,
(9,1,0,0), (10,0,0,0)]

解决方案 7:

Martin Valgur的答案允许在目标子项已超出时提前退出。这假设输入没有负数。

然而,这种方法可以扩展以涵盖负值:

  • 在预处理阶段,为每个索引注册从该点开始的最小和最大可能的总和

  • 在找到中途好的组合后,也要继续搜索,因为它可能会进一步扩展。

我还会避免在每次递归调用时创建新列表。您可以延迟此操作,直到真正拥有有效组合,然后才为其创建新列表。

def subset_sum(numbers, target):
    partial = []  # Commonly shared in recursive search tree
    # Preprocessing to allow early exit, also when there are negative values in the input
    acc = 0
    least = [acc := acc + min(val, 0) for val in reversed(numbers)][::-1]
    acc = 0
    most = [acc := acc + max(val, 0) for val in reversed(numbers)][::-1]
    n = len(numbers)

    def recur(i, target):
        if i >= n or not (least[i] <= target <= most[i]):
            if target == 0:
                # Provide a new list, so that if consumer mutates it, it does not affect us
                yield partial[:]
            return  # No hope of reaching zero anymore
        yield from recur(i + 1, target)  # Combis without numbers[i] 
        partial.append(numbers[i])  # Mutate
        yield from recur(i + 1, target - numbers[i])
        partial.pop()  # Backtrack

    return recur(0, target)

# Example extended with values -6 and -10.
print(list(subset_sum([1, 2, 3, 7, 7, 9, -6, -10], 10)))

对于扩展示例(包括值 -6 和 -10),这将输出以下列表:

[
    [7, 9, -6], 
    [7, 9, -6], 
    [3, 7], 
    [3, 7], 
    [3, 7, 7, 9, -6, -10], 
    [2, 7, 7, -6], 
    [1, 9], 
    [1, 3, 7, 9, -10], 
    [1, 3, 7, 9, -10], 
    [1, 2, 7], 
    [1, 2, 7], 
    [1, 2, 7, 7, 9, -6, -10], 
    [1, 2, 3, 7, 7, -10]
]
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1325  
  IPD(Integrated Product Development)流程作为一种先进的产品开发管理模式,在众多企业中得到了广泛应用。它涵盖了从产品概念产生到产品退市的整个生命周期,通过整合跨部门团队、优化流程等方式,显著提升产品开发的效率和质量,进而为项目的成功奠定坚实基础。深入探究IPD流程的五个阶段与项目成功之间...
IPD流程分为几个阶段   4  
  华为作为全球知名的科技企业,其成功背后的管理体系备受关注。IPD(集成产品开发)流程作为华为核心的产品开发管理模式,其中的创新管理与实践更是蕴含着丰富的经验和深刻的智慧,对众多企业具有重要的借鉴意义。IPD流程的核心架构IPD流程旨在打破部门墙,实现跨部门的高效协作,将产品开发视为一个整体的流程。它涵盖了从市场需求分析...
华为IPD是什么   3  
  IPD(Integrated Product Development)研发管理体系作为一种先进的产品开发模式,在众多企业的发展历程中发挥了至关重要的作用。它不仅仅是一套流程,更是一种理念,一种能够全方位提升企业竞争力,推动企业持续发展的有效工具。深入探究IPD研发管理体系如何助力企业持续发展,对于众多渴望在市场中立足并...
IPD管理流程   3  
  IPD(Integrated Product Development)流程管理旨在通过整合产品开发流程、团队和资源,实现产品的快速、高质量交付。在这一过程中,有效降低成本是企业提升竞争力的关键。通过优化IPD流程管理中的各个环节,可以在不牺牲产品质量和性能的前提下,实现成本的显著降低,为企业创造更大的价值。优化产品规划...
IPD流程分为几个阶段   4  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用