次の文字列が2桁異なる、長さnのバイナリ文字列とk個のバイナリ文字列のシーケンスを生成するアルゴリズムについて疑問に思っています。
例えば:
11100
11010
11001
10101
10110
10011
00111
01011
01101
01110
11100
もちろん、すべてのn \choose k
バイナリ文字列を使用する必要があります。
これは再帰を使用して設定できると思います。
私は次のアイデンティティに触発されました:
choose(n,k) = choose(n-1,k-1) + choose(n-1,k)
したがって、要求されたシーケンス(つまり、連続する文字列が2ビット異なるように正確にkビットが設定された長さnのバイナリ文字列のシーケンス)を生成する関数F(n、k)を定義します。
まず、F(n、k)の列を好きなように並べ替えて、同じように有効な別のF(n、k)を生成できることを確認します。
上記の同一性は、F(n-1、k-1)とF(n-1、k)を使用してF(n、k)を構築することを示唆しています。最後の文字列がk-1sで終わるように、F(n-1、k-1)の列を並べ替えて、それぞれ1
にaを追加して、 Aを取得した文字列1
とします。最初の文字列がksで終わるように、F(n-1、k)の列を並べ替えて、それぞれ1
にaを追加して得られる文字列をBとします0
。その場合、F(n、k)はAとBの単なる連結です。結果は有効なF(n、k)です。これは、AとBの内部で、文字列が2ビット異なり、Aの最後の文字列と最初の文字列が異なるためです。 Bの文字列は2ビット異なります(k + 1番目から最後のビットと最後のビット)。
n = 5、k=2を使用した例を示します。次の2つのFシーケンスを再帰的に取得します。
F(4,1): 0001
0010
0100
1000
F(4,2): 0011
0101
1001
1010
0110
1100
Aを作成するには、F(4,1)の最初と最後の列を入れ替えて、1
それぞれに追加します。
A: 10001
00101
01001
00011
Bを作成するには、列を入れ替える必要がないため、0
F(4,2)の各行にaを追加するだけです。
B: 00110
01010
10010
10100
01100
11000
その場合、F(5,2)はAとBの単なる連結です。
この種の順列に関する私のブログ投稿(とりわけ)を読んで、より多くの背景を取得する必要があります-そしてそこにあるリンクのいくつかをたどってください。
これは、Steinhaus–Johnson–Trotter順列ジェネレーターの生成シーケンスの後に作成された辞書式順列ジェネレーターのバージョンであり、要求どおりに実行されます。
def l_perm3(items):
'Generator yielding Lexicographic permutations of a list of items'
if not items:
yield [[]]
else:
dir = 1
new_items = []
this = [items.pop()]
for item in l_perm(items):
lenitem = len(item)
try:
# Never insert 'this' above any other 'this' in the item
maxinsert = item.index(this[0])
except ValueError:
maxinsert = lenitem
if dir == 1:
# step down
for new_item in [item[:i] + this + item[i:]
for i in range(lenitem, -1, -1)
if i <= maxinsert]:
yield new_item
else:
# step up
for new_item in [item[:i] + this + item[i:]
for i in range(lenitem + 1)
if i <= maxinsert]:
yield new_item
dir *= -1
from math import factorial
def l_perm_length(items):
'''\
Returns the len of sequence of lexicographic perms of items.
Each item of items must itself be hashable'''
counts = [items.count(item) for item in set(items)]
ans = factorial(len(items))
for c in counts:
ans /= factorial(c)
return ans
if __name__ == '__main__':
n = [1, 1, 1, 0, 0]
print '\nLexicograpic Permutations of %i items: %r' % (len(n), n)
for i, x in enumerate(l_perm3(n[:])):
print('%3i %r' % (i, x))
assert i+1 == l_perm_length(n), 'Generated number of permutations is wrong'
上記のプログラムからの出力は、たとえば次のとおりです。
Lexicograpic Permutations of 5 items: [1, 1, 1, 0, 0]
0 [1, 1, 1, 0, 0]
1 [1, 1, 0, 1, 0]
2 [1, 0, 1, 1, 0]
3 [0, 1, 1, 1, 0]
4 [0, 1, 1, 0, 1]
5 [1, 0, 1, 0, 1]
6 [1, 1, 0, 0, 1]
7 [1, 0, 0, 1, 1]
8 [0, 1, 0, 1, 1]
9 [0, 0, 1, 1, 1]
0
ます1
。0000 1001 0011 1010 0110 1111 0101 1100
これにより、nビット文字列のちょうど半分が生成されます。これはあなたが得ることができる最も多いものです-たとえば、すべての文字列で始まり0
、一度に2ビットを変更すると、常に偶数の1
'が存在するため、残りの半分は生成できません。