我想创建n个项目的所有可能的分布。这是指众所周知的鸽洞原理。
以下值是Microsoft Excel的结果:
get_distributions(list, number_of_items_to_distribute)
get_distributions([], 1) = [[1]]
get_distributions([], 2) = [[1, 1], [2]]
get_distributions([], 3) = [[1, 1, 1], [1, 2], [2, 1], [3]]
get_distributions([], 4) = [[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]]
我已经有一些代码,但是删除临时列表存在一些问题。
all_distributions = []
def get_distributions(distribution, items):
print('call with distribution = ' + str(distribution) + ', items = ' + str(items))
print('---------------')
# base case
if items == 0:
all_distributions.append(distribution)
print('end: ' + str(distribution))
distribution.clear()
return []
# recursion
else:
for i in range(1, items + 1):
distribution.append(i)
get_distributions(distribution, items - i)
这样,我可以在“ end:”之后打印出良好的结果,但是缺少诸如[1,2](n = 3的调用)之类的值。除此之外,这些值不会附加到我的all_distributions中。
我对尝试解决此问题的方式感兴趣。这是一个好方法还是我绝对错误?
最佳答案
您的代码的主要问题是列表all_distributions
最终包含对同一输入列表distribution
的许多引用。当您调用all_distributions.append(distribution)
时,列表distribution
不会复制到列表all_distributions
中,而仅附加了对该列表的引用。您可以通过显式插入副本来解决此问题:all_distributions.append(list(distribution))
对代码的最小修复是插入副本,在基本情况下删除distribution.clear()
,然后在递归调用后添加distribution.pop()
:
all_distributions = []
def get_distributions(distribution, items):
if items == 0:
all_distributions.append(list(distribution))
else:
for i in range(1, items + 1):
distribution.append(i)
get_distributions(distribution, items - i)
distribution.pop()
get_distributions([], 3)
print(all_distributions)
输出:
[[1, 1, 1], [1, 2], [2, 1], [3]]
更好的方法是避免使用
distribution.append
,而是在列表上使用加号运算符,如下所示:def get_distributions(distribution, items):
if items == 0:
all_distributions.append(distribution)
else:
for i in range(1, items + 1):
d = distribution + [i]
get_distributions(d, items - i)
列表上的加号运算符通过串联两个给定列表来创建新列表。在这种情况下,我们将在
i
的右侧连接单个元素distribution
,以获得一个新副本,其中包含distribution
中的元素,后跟i
。另一个改进是避免使用全局变量
all_distributions
,而是返回分发列表:def get_distributions(distribution, items):
if items == 0:
return [distribution]
else:
all_distributions = []
for i in range(1, items + 1):
d = distribution + [i]
all_distributions += get_distributions(d, items - i)
return all_distributions
print(get_distributions([], 4))
输出:
[[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]]