[英]Find all possible subsets that sum up to a given number
I'm learning Python and I have a problem with this seems to be simple task. 我正在学习Python,对此问题似乎很简单。
I want to find all possible combination of numbers that sum up to a given number. 我想找到所有总计给定数字的可能组合。
for example: 4 -> [1,1,1,1] [1,1,2] [2,2] [1,3] 例如:4-> [1,1,1,1] [1,1,2] [2,2] [1,3]
I pick the solution which generate all possible subsets (2^n) and then yield just those that sum is equal to the number. 我选择生成所有可能的子集(2 ^ n)的解决方案,然后得出总和等于数字的那些子集。 I have a problem with the condition. 我的状况有问题。 Code: 码:
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 is it a good approach? BTW是个好方法吗?
Here's some code I saw a few years ago that does the trick: 这是几年前我看到的一些实现此目的的代码:
>>> 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]]
Additional References: 其他参考文献:
That solution doesn't work, right? 该解决方案不起作用,对吗? It will never add a number to a subset more than once, so you will never get, for example, [1,1,2]. 它永远不会将一个数字加到子集上一次,因此您将永远不会得到例如[1,1,2]。 It will never skip a number, either, so you will never get, for example, [1,3]. 它也永远不会跳过数字,因此您永远也不会得到例如[1,3]。
So the problem with your solution is twofold: One, you are not actually generating all possible subsets in the range 1..number. 因此,解决方案存在两个问题:第一,实际上并没有生成1..number范围内的所有可能子集。 Two, The set of all subsets will exclude things that you should be including, because it will not allow a number to appear more than once. 第二,所有子集的集合将排除您应包括的内容,因为它不允许数字出现多次。
This kind of problem can be generalized as a search problem. 这种问题可以概括为搜索问题。 Imagine that the numbers you want to try are nodes on a tree, and then you can use depth-first search to find all paths through the tree that represent a solution. 想象一下,您想尝试的数字是一棵树上的节点,然后您可以使用深度优先搜索来找到代表该解决方案的所有路径。 It's an infinitely large tree, but luckily, you never need to search all of it. 它是一棵无限大的树,但是幸运的是,您不需要搜索所有的树。
Here is an alternate approach which works by taking a list of all 1s and recursively collapsing it by adding subsequent elements, this should be more efficient than generating all possible subsets: 这是一种替代方法,该方法通过获取全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]]
You can strip off the last value if you don't want the trivial case. 如果您不希望出现这种情况,则可以去除最后一个值。 If you will just be looping over the results remove the list
call and just return the generator. 如果您只是要遍历结果,请删除list
调用并返回生成器。
This is equivalent to the problem described in this question and can use a similar solution. 这等效于此问题中描述的问题,并且可以使用类似的解决方案。
To elaborate: 详细说明:
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
That translates this question into that question and back again. 这就把这个问题翻译成那个问题,然后又回来了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.