繁体   English   中英

查找所有总计为给定数字的可能子集

[英]Find all possible subsets that sum up to a given number

我正在学习Python,对此问题似乎很简单。

我想找到所有总计给定数字的可能组合。
例如:4-> [1,1,1,1] [1,1,2] [2,2] [1,3]

我选择生成所有可能的子集(2 ^ n)的解决方案,然后得出总和等于数字的那些子集。 我的状况有问题。 码:

def allSum(number):
    #mask = [0] * number
    for i in xrange(2**number):
        subSet = []
        for j in xrange(number):
            #if :
                subSet.append(j)
        if sum(subSet) == number:
           yield subSet



for i in allSum(4):
    print i   

BTW是个好方法吗?

这是几年前我看到的一些实现此目的的代码:

>>> def partitions(n):
        if n:
            for subpart in partitions(n-1):
                yield [1] + subpart
                if subpart and (len(subpart) < 2 or subpart[1] > subpart[0]):
                    yield [subpart[0] + 1] + subpart[1:]
        else:
            yield []

>>> print list(partitions(4))
[[1, 1, 1, 1], [1, 1, 2], [2, 2], [1, 3], [4]]

其他参考文献:

该解决方案不起作用,对吗? 它永远不会将一个数字加到子集上一次,因此您将永远不会得到例如[1,1,2]。 它也永远不会跳过数字,因此您永远也不会得到例如[1,3]。

因此,解决方案存在两个问题:第一,实际上并没有生成1..number范围内的所有可能子集。 第二,所有子集的集合将排除您应包括的内容,因为它不允许数字出现多次。

这种问题可以概括为搜索问题。 想象一下,您想尝试的数字是一棵树上的节点,然后您可以使用深度优先搜索来找到代表该解决方案的所有路径。 它是一棵无限大的树,但是幸运的是,您不需要搜索所有的树。

这是一种替代方法,该方法通过获取全1的列表并通过添加后续元素来递归折叠它来工作,这比生成所有可能的子集更有效:

def allSum(number):
    def _collapse(lst):
        yield lst
        while len(lst) > 1:
            lst = lst[:-2] + [lst[-2] + lst[-1]]
            for prefix in _collapse(lst[:-1]):
                if not prefix or prefix[-1] <= lst[-1]:
                    yield prefix + [lst[-1]]
    return list(_collapse([1] * number))

>>> allSum(4)
[[1, 1, 1, 1], [1, 1, 2], [2, 2], [1, 3], [4]]
>>> allSum(5)
[[1, 1, 1, 1, 1], [1, 1, 1, 2], [1, 2, 2], [1, 1, 3], [2, 3], [1, 4], [5]]

如果您不希望出现这种情况,则可以去除最后一个值。 如果您只是要遍历结果,请删除list调用并返回生成器。

这等效于此问题中描述的问题,并且可以使用类似的解决方案。

详细说明:

def allSum(number):
    for solution in possibilites(range(1, number+1), number):
        expanded = []
        for value, qty in zip(range(1, number+1), solution):
            expanded.extend([value]*qty)
        yield expanded

这就把这个问题翻译成那个问题,然后又回来了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM