我有兴趣找到一个简单的公式来确定自然数序列中特定 bit_count 出现的第 n 次。K
具体来说,和之间的关系N
如下表所示。那么,例如,什么是N
,K=123456789123456789123456789
我可以告诉你M
是50
,但是什么是N
?
length = 5
for K in range(2**length):
bits = bin(K)[2:].zfill(length)
M = K.bit_count() # numbers of "1"s in the binary sequence
N = sum(1 for i in range(K) if M==i.bit_count())
print(f'{K: <2}',bits,M,N)
'''
K bits M N
0 00000 0 0
1 00001 1 0
2 00010 1 1
3 00011 2 0
4 00100 1 2
5 00101 2 1
6 00110 2 2
7 00111 3 0
8 01000 1 3
9 01001 2 3
10 01010 2 4
11 01011 3 1
12 01100 2 5
13 01101 3 2
14 01110 3 3
15 01111 4 0
16 10000 1 4
17 10001 2 6
18 10010 2 7
19 10011 3 4
20 10100 2 8
21 10101 3 5
22 10110 3 6
23 10111 4 1
24 11000 2 9
25 11001 3 7
26 11010 3 8
27 11011 4 2
28 11100 3 9
29 11101 4 3
30 11110 4 4
31 11111 5 0
...
'''
这样看来,我已经解决了一半了。看起来
N = (K-sum(2**i for i in range(M)).bit_count()
每当N<=M
。这似乎是因为,
K = sum(2**i for i in range(M)) + sum(2**(M-1-i) for i in range(N))
再次,每当N<=M
。看起来N<=M
大约有一半的情况会发生这种情况。
length = 5
for K in range(2**length):
bits = bin(K)[2:].zfill(length)
M = K.bit_count() # numbers of "1"s in the binary sequence
N = sum(1 for i in range(K) if M==i.bit_count())
if N <= M:
A = sum(2**i for i in range(M)) + sum(2**(M-1-i) for i in range(N))
B = (K - sum(2**i for i in range(M))).bit_count()
else:
A = '-'
B = '-'
print(f'{K: <2}',bits,M,N,A,B)
我不懂 Python,所以这是 Ruby。该算法应该易于翻译。这个想法是,对于每个设置位(从小到大),计算该位左侧相同的所有数字,该位及其右侧具有相同数量的设置位,但没有该位已设置。
代码:
结果:
对于你的大例子:
简单的解决方案:
k
但是,您可以尝试仅生成具有特定位计数的所有数字 <并对其进行计数。这是一个简单的尝试:
这是可行的,但效率非常低,因为它仍然必须生成所有不唯一的排列。最后,生成排列比仅仅计算位数要慢得多。
相反,最好为具有一定数量 1 的数字生成 0 位置的唯一组合,然后计算这些数字:
然而,简单的解决方案使用的操作非常高效,只测试所有数字而不是找出要避免的数字会更有效。
尝试运行这个:
您会发现这
count_same0
很容易是最快的(事实上,只是简单的快)并且count_same2
比 更好count_same1
,但不接近count_same0
。所以我认为简单的答案确实是:
但是,对于您的示例值
123456789123456789123456789
,这将需要很长时间才能完成。我怀疑是否有一个已知的更简单的解决方案,因为(在如上所述解决它之后)我也在 OEIS 上找到了序列:https://oeis.org/A079071并且它基本上定义了相同的东西。(看看图表,它并没有变得更好:https://oeis.org/A079071/graph)谁或什么任务让你去解决这个问题?
将数字表示为位的组合并计算组合索引:
输出(与戴夫的相同):
啊该死,我刚刚意识到你正在追求“一个简单的公式”。那好吧。也许这对于来这里寻找简单代码的人来说仍然有用。