第一个问题的答案很简单:就是C(n,r)
,我们r
要从一组 size 中选择所有项目的组合n
。公式在其他地方:
C(n,r) = n! / (r! (n-r)!)
选择i'th
组合而不计算所有其他组合的能力将取决于是否具有将组合编号i
与组合相关联的编码。这将更具挑战性,需要更多的思考......
(编辑)
在对问题进行了更多思考之后,Python 中的解决方案如下所示:
from math import factorial
def combination(n,r):
return factorial(n) / (factorial(r) * factorial(n-r))
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def showComb(n,r,i,a):
if r < 1:
return ""
rr = r-1
nn = max(n-1,rr)
lasti = i
i -= combination(nn,rr)
j = 0
while i > 0:
j += 1
nn = max(nn-1,1)
rr = min(rr,nn) # corrected this line in second edit
lasti = i
i -= combination(nn,rr)
return a[j] + showComb(n-j-1,r-1,lasti,a[(j+1):])
for i in range(10):
print(showComb(5,3,i+1,alphabet))
...输出问题中显示的列表。
我使用的方法是找到i'th
输出集合的第一个元素,使用剩余集合元素的组合数可用于查找给定 number 的第一个元素的想法i
。
也就是说,对于 C(5,3),第一个 C(4,2) (=6) 输出集的第一个字符为 'A',然后下一个 C(3,1) (=3) 输出集具有'B' 然后 C(1,1) (=1) 集合将 'C' 作为它们的第一个字符。
然后该函数递归地找到剩余的元素。请注意,它showComb()
是尾递归的,因此如果您愿意,可以将其表示为循环,但我认为在这种情况下递归版本更容易理解。
为了进一步测试,以下代码可能有用:
import itertools
def showCombIter(n,r,i,a):
return ''.join(list(itertools.combinations(a[0:n],r))[i-1])
print ("\n")
# Testing for other cases
for i in range(120):
x = showComb(10,3,i+1,alphabet)
y = showCombIter(10,3,i+1,alphabet)
print(i+1,"\t",x==y,"\t",x,y)
...这证实了这个案例的所有 120 个例子都是正确的。
我没有准确计算时间复杂度,但调用次数showComb()
将是r
并且while
循环将执行n
次数或更少。因此,在问题的术语中,如果我们假设函数可以在恒定时间内计算,我很确定复杂度将小于 O(M+N),factorial()
我认为这不是一个糟糕的近似值,除非它的实现是幼稚的。