我想知道算法生成长度为 n 的二进制字符串序列,其中下一个字符串以两位数不同。
例如:
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)
因此,我们定义了一个函数 F(n,k),它产生所请求的序列(即,长度为 n 的二进制字符串序列,恰好设置了 k 位,使得连续的字符串相差两位)。
首先,观察我们可以以任何我们喜欢的方式重新排序 F(n,k) 的列,并产生另一个同样有效的 F(n,k)。
上面的恒等式表明我们使用 F(n-1,k-1) 和 F(n-1,k) 构建 F(n,k)。令 A 是通过重新排序 F(n-1,k-1) 的列获得的字符串,以便最后一个字符串以 k-1 1
s 结尾,然后将 a 添加1
到每个字符串。令 B 是通过重新排序 F(n-1,k) 的列获得的字符串,使第一个字符串以 k 1
s 结尾,然后将 a 添加0
到每个字符串。那么 F(n,k) 只是 A 和 B 的串联。结果是有效的 F(n,k),因为在 A 和 B 内部,字符串相差两位,A 的最后一个字符串和第一个字符串B 的字符串相差两位(第 k+1 到最后一位和最后一位)。
我将展示一个使用 n=5,k=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 位字符串。这是你能得到的最多 - 另一半无法生成,因为例如,从一串 all 0
's 开始并一次更改两位,总会有偶数个1
's。