获取一个数字的所有整数分区



我基本上有这个问题,获取所有加起来为一个数字的数字,但我也需要包含0。

我已经尝试了公认的答案,并使其从0开始,基本上就像一样

def sum_to_n(n, size, limit=None):
"""Produce all lists of `size` positive integers in decreasing order
that add up to `n`."""
if size == 1:
yield [n]
return
if limit is None:
limit = n
start = 0
stop = min(limit, n - size + 1) + 1
for i in range(start, stop):
for tail in sum_to_n(n - i, size - 1, i):
yield [i] + tail

对于较小的数字来说效果很好,但当我有较大的数字作为目标时,它开始表现得很奇怪。例如:

for partition in sum_to_n(10,7):
print(partition)

输出类似

0   0   0   0   0   0   10
1   0   0   0   0   0   9
1   1   0   0   0   0   8
1   1   1   0   0   0   7
1   1   1   1   0   0   6
1   1   1   1   1   0   5
1   1   1   1   1   1   4
2   0   0   0   0   0   8
2   1   0   0   0   0   7
2   1   1   0   0   0   6
2   1   1   1   0   0   5
2   1   1   1   1   0   4
2   1   1   1   1   1   3
2   2   0   0   0   0   6
2   2   1   0   0   0   5
2   2   1   1   0   0   4
2   2   1   1   1   0   3
2   2   1   1   1   1   2
2   2   2   0   0   0   4
2   2   2   1   0   0   3
2   2   2   1   1   0   2
2   2   2   1   1   1   1
3   0   0   0   0   0   7
3   1   0   0   0   0   6
3   1   1   0   0   0   5
3   1   1   1   0   0   4
3   1   1   1   1   0   3
3   1   1   1   1   1   2
3   2   0   0   0   0   5
3   2   1   0   0   0   4
3   2   1   1   0   0   3
3   2   1   1   1   0   2
3   2   1   1   1   1   1
4   0   0   0   0   0   6
4   1   0   0   0   0   5
4   1   1   0   0   0   4
4   1   1   1   0   0   3
4   1   1   1   1   0   2
4   1   1   1   1   1   1

这里显然没有包括5 5 0 0 0 0的情况。它也有重复的情况,比如11 11 11 14和4 11 11 11 11,我不想要。这个代码出了什么问题?我如何修改它或对如何解决问题有任何其他想法?谢谢

我想这就是你想要的:

def sum_to_n2(n, size, limit=None):
if limit is None:
limit = n
if size == 1:
if n <= limit:
yield[n]
else:
for i in range(0, limit+1):
for tail in sum_to_n2(n - i, size - 1, min(i, n-i)):
yield[i] + tail

print(list(sum_to_n2(10, 7)))

与您的代码的差异:

  • 在开始时检查limit is None,该函数有一个更简单的if .. else(主要是装饰性的,我觉得更容易理解,return不需要离开那里(
  • 如果size == 1,则总是产生[n],但这应该只在n <= limit的情况下发生
  • 你将范围的极限计算为min(limit, n - size + 1) + 1,但这很难在心理上跟踪(更重要的是,范围刚好停在它附近(;我只是说,极限是i(我们要添加到序列中的数字,所以不再允许更大的数字(和n-i(余数,我们不再需要比这更大的数(的最小值,并将其传递给min(i, n-i)的递归调用

我还没有完成计算错误在代码中的位置的完整逻辑,但如果我将n <= limit条件添加到代码中,它将不再包括零。我相信你可以在将值与我的算法实现进行比较时弄清楚,但我认为我的算法有点干净,所以更可取。

6, 3的输出已经显示了代码的问题,该代码比10, 7短。sum_to_n(5, 3):的输出

[[0, 0, 5], [1, 0, 4], [1, 1, 3], [2, 0, 3], [2, 1, 2], [2, 2, 1], [3, 0, 2], [3, 1, 1]]

例如,请注意[2, 1, 2][2, 2, 1]中的重复项。

我的sum_to_n2(5, 3):输出

[[2, 2, 1], [3, 1, 1], [3, 2, 0], [4, 1, 0], [5, 0, 0]]

就我个人而言,但这纯粹是风格,我更喜欢这个修改后的实现的输出:

def sum_to_n2(n, size, limit=None):
if limit is None:
limit = n
if size == 1:
if n <= limit:
yield[n]
else:
for i in range(limit, -1, -1):
for tail in sum_to_n2(n - i, size - 1, min(i, n - i)):
yield[i] + tail

结果(对于sum_to_n2(5, 3)(:

[[5, 0, 0], [4, 1, 0], [3, 2, 0], [3, 1, 1], [2, 2, 1]]

它通过反转for循环中的范围来实现这一点。

顺便说一句,这里有一个非递归的一行代码可以做到这一点,但它慢得像泥一样:(:

def sum_to_n_one_liner (n, sized):
set(tuple(sorted(t)) for t in filter(lambda s: sum(s) == n, product(*[range(n)]*size)))

它的工作原理是天真地做需要做的事情:

  • 取0到n的数字,size
  • 计算笛卡尔乘积,得到这些数字的所有可能组合
  • 只保留总和为n
  • 对生成的元组进行排序,只保留唯一的元组

为了不得到重复的分区,您可以定义函数,使其只生成非递减顺序的结果。

def partition(N,size):
if size == 1 :
yield (N,)                           # base case, only 1 part
return
for a in range(N//size+1):               # smaller part followed by
for p in partition(N-a*size,size-1): # equal or larger ones
yield (a, *(n+a for n in p))     # recursing on delta only

输出:

for p in partition(10,7): print(p)
(0, 0, 0, 0, 0, 0, 10)
(0, 0, 0, 0, 0, 1, 9)
(0, 0, 0, 0, 0, 2, 8)
(0, 0, 0, 0, 0, 3, 7)
(0, 0, 0, 0, 0, 4, 6)
(0, 0, 0, 0, 0, 5, 5)
(0, 0, 0, 0, 1, 1, 8)
(0, 0, 0, 0, 1, 2, 7)
(0, 0, 0, 0, 1, 3, 6)
(0, 0, 0, 0, 1, 4, 5)
(0, 0, 0, 0, 2, 2, 6)
(0, 0, 0, 0, 2, 3, 5)
(0, 0, 0, 0, 2, 4, 4)
(0, 0, 0, 0, 3, 3, 4)
(0, 0, 0, 1, 1, 1, 7)
(0, 0, 0, 1, 1, 2, 6)
(0, 0, 0, 1, 1, 3, 5)
(0, 0, 0, 1, 1, 4, 4)
(0, 0, 0, 1, 2, 2, 5)
(0, 0, 0, 1, 2, 3, 4)
(0, 0, 0, 1, 3, 3, 3)
(0, 0, 0, 2, 2, 2, 4)
(0, 0, 0, 2, 2, 3, 3)
(0, 0, 1, 1, 1, 1, 6)
(0, 0, 1, 1, 1, 2, 5)
(0, 0, 1, 1, 1, 3, 4)
(0, 0, 1, 1, 2, 2, 4)
(0, 0, 1, 1, 2, 3, 3)
(0, 0, 1, 2, 2, 2, 3)
(0, 0, 2, 2, 2, 2, 2)
(0, 1, 1, 1, 1, 1, 5)
(0, 1, 1, 1, 1, 2, 4)
(0, 1, 1, 1, 1, 3, 3)
(0, 1, 1, 1, 2, 2, 3)
(0, 1, 1, 2, 2, 2, 2)
(1, 1, 1, 1, 1, 1, 4)
(1, 1, 1, 1, 1, 2, 3)
(1, 1, 1, 1, 2, 2, 2)

最新更新