Python子集总和
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23087820/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python Subset Sum
提问by Chase McCoy
I am trying to write a function that will not only determine whether the sum of a subset of a set adds to a desired target number, but also to print the subset that is the solution.
我正在尝试编写一个函数,该函数不仅可以确定集合子集的总和是否与所需的目标数相加,而且还可以打印作为解决方案的子集。
Here is my code for finding whether a subset exists:
这是我用于查找子集是否存在的代码:
def subsetsum(array,num):
if num == 0 or num < 1:
return False
elif len(array) == 0:
return False
else:
if array[0] == num:
return True
else:
return subsetsum(array[1:],(num - array[0])) or subsetsum(array[1:],num)
How can I modify this to record the subset itself so that I can print it? Thanks in advance!
如何修改它以记录子集本身以便我可以打印它?提前致谢!
采纳答案by Samy Arous
Based on your solution:
根据您的解决方案:
def subsetsum(array,num):
if num == 0 or num < 1:
return None
elif len(array) == 0:
return None
else:
if array[0] == num:
return [array[0]]
else:
with_v = subsetsum(array[1:],(num - array[0]))
if with_v:
return [array[0]] + with_v
else:
return subsetsum(array[1:],num)
回答by jonrsharpe
You could change your approach to do that more easily, something like:
你可以改变你的方法来更容易地做到这一点,比如:
def subsetsum(array, num):
if sum(array) == num:
return array
if len(array) > 1:
for subset in (array[:-1], array[1:]):
result = subsetsum(subset, num)
if result is not None:
return result
This will return either a valid subset or None
.
这将返回一个有效的子集或None
.
回答by Reut Sharabani
Thought I'll throw another solution into the mix.
以为我会加入另一个解决方案。
We can map each selection of a subset of the list to a (0-padded) binary number, where a 0 means not taking the member in the corresponsing position in the list, and 1 means taking it.
我们可以将列表子集的每个选择映射到一个(0 填充的)二进制数,其中 0 表示不占用列表中相应位置的成员,1 表示占用它。
So masking [1, 2, 3, 4]
with 0101
creates the sub-list [2, 4]
.
因此屏蔽[1, 2, 3, 4]
with0101
创建子列表[2, 4]
。
So, by generating all 0-padded binary numbers in the range between 0 and 2^LENGTH_OF_LIST, we can iterate all selections. If we use these sub-list selections as masks and sum the selection - we can know the answer.
因此,通过生成 0 到 2^LENGTH_OF_LIST 范围内的所有 0 填充二进制数,我们可以迭代所有选择。如果我们使用这些子列表选择作为掩码并对选择求和 - 我们可以知道答案。
This is how it's done:
这是它的完成方式:
#!/usr/bin/env python
# use a binary number (represented as string) as a mask
def mask(lst, m):
# pad number to create a valid selection mask
# according to definition in the solution laid out
m = m.zfill(len(lst))
return map(lambda x: x[0], filter(lambda x: x[1] != '0', zip(lst, m)))
def subset_sum(lst, target):
# there are 2^n binary numbers with length of the original list
for i in xrange(2**len(lst)):
# create the pick corresponsing to current number
pick = mask(lst, bin(i)[2:])
if sum(pick) == target:
return pick
return False
print subset_sum([1,2,3,4,5], 7)
Output:
输出:
[3, 4]
To return all possibilities we can use a generator instead (the only changes are in subset_sum
, using yield
instead of return
and removing return False
guard):
为了返回所有的可能性,我们可以使用一个生成器来代替(唯一的变化是在subset_sum
,使用yield
而不是return
和移除return False
守卫):
#!/usr/bin/env python
# use a binary number (represented as string) as a mask
def mask(lst, m):
# pad number to create a valid selection mask
# according to definition in the solution laid out
m = m.zfill(len(lst))
return map(lambda x: x[0], filter(lambda x: x[1] != '0', zip(lst, m)))
def subset_sum(lst, target):
# there are 2^n binary numbers with length of the original list
for i in xrange(2**len(lst)):
# create the pick corresponsing to current number
pick = mask(lst, bin(i)[2:])
if sum(pick) == target:
yield pick
# use 'list' to unpack the generator
print list(subset_sum([1,2,3,4,5], 7))
Output:
输出:
[[3, 4], [2, 5], [1, 2, 4]]
Note:While not padding the mask with zeros may work as well, as it will simply select members of the original list in a reverse order - I haven't checked it and didn't use it.
注意:虽然不用零填充掩码也可能有效,因为它只会以相反的顺序选择原始列表的成员 - 我没有检查它也没有使用它。
I didn't use it since it's less obvious (to me) what's going on with such trenary-like mask (1, 0 or nothing) and I rather have everything well defined.
我没有使用它,因为它不太明显(对我来说)这种类似 trenary 的掩码(1、0 或什么都没有)发生了什么,我宁愿让一切都得到很好的定义。
回答by harry
Slightly modified version of Samy's answer to print all possible combinations.
Samy 的答案的稍微修改版本以打印所有可能的组合。
def subset(array, num):
result = []
def find(arr, num, path=()):
if not arr:
return
if arr[0] == num:
result.append(path + (arr[0],))
else:
find(arr[1:], num - arr[0], path + (arr[0],))
find(arr[1:], num, path)
find(array, num)
return result