获取数字的所有整数分区
get all integer partition of a number
我基本上有这个问题Get all numbers that add up to a number但我还需要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 0 的情况。它还有像 1 1 1 1 1 1 4 和 4 1 1 1 1 1 1 这样的重复情况,我不想要.这段代码有什么问题?我该如何修改它或关于如何解决问题的任何其他想法?谢谢!
我想这就是你想要的:
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)
我基本上有这个问题Get all numbers that add up to a number但我还需要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 0 的情况。它还有像 1 1 1 1 1 1 4 和 4 1 1 1 1 1 1 这样的重复情况,我不想要.这段代码有什么问题?我该如何修改它或关于如何解决问题的任何其他想法?谢谢!
我想这就是你想要的:
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)