最初の質問への答えは簡単です: それは、 size のセットからアイテムC(n,r)
のすべての組み合わせを選択する場所です。式は他の場所の中でもここにあります:r
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
、残りのセット要素の組み合わせの数を使用して、特定の番号の最初の要素であるべき要素を見つけることができるという考えを使用して、出力セットの最初の要素を見つけることi
です。
つまり、C(5,3) の場合、最初の C(4,2) (=6) 出力セットは最初の文字として 'A' を持ち、次の C(3,1) (=3) 出力セットは'B' then 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
1 回またはそれ以下で実行されます。factorial()
したがって、質問の用語では、関数が一定時間で計算できると仮定すると、複雑さは O(M+N) 未満になると確信しています。その実装は単純です。