以前のワンライナー ソリューション、
n ^ sum(2**i for i in range(0, len(bin(n))-2, 2))
は O(lg n) の解で、n は入力数です。以下に示す漸近的にはるかに高速なソリューションは、時間 O(lg(lg n)) で実行されます。つまり、入力数値のビット数の対数に比例する時間で実行されます。示されている二分探索はテストでは問題なく動作しましたが、おそらく改善される可能性があることに注意してください。
編集:式-1<<L
は、上位ビットが設定され、L 下位ビットがクリアされたマスクです。たとえば、python は の値として 255 を表示し、 の値(-1<<8)&255
として 256 を表示します(-1<<8)&256
。プログラムは、L が数値 v のビット数を超えるまで、L を 2 倍にする (より多くの下位ビットをクリアする) ことから始めます。つまり、until(-1<<L)&v
はゼロです。L が 2 倍になるたびに、R を上に移動できます。次に、プログラムは二分探索を使用して、LR 差を繰り返し半分にし、 となるような L=R+1 を見つけてv&(-1<<L) == 0
、v&(-1<<R) > 0
v が L ビット長であることを確立します。その後、プログラムは、少なくとも L ビットの長さになるまで、交互ビット マスク k の長さを 2 倍にします。次に、L が奇数の場合、マスクを 1 ビットシフトします。(代わりにif L & 1: k = k<<1
言うことができますk <<= L&1
. 「代替ビット」は、MSB のすぐ下のビットから始まると解釈したことに注意してください。代わりにビット 0,2,4... を常にトグルするには、行を削除します。) 次に、 で & することにより、つまり (2**L)-1if L & 1: k = k<<1
で k の下位 L ビットを取り出します。(1<<L)-1
プログラムの O(lg(lg n)) 時間制限は O(1) 論理演算に依存することに注意してください。しかし、L が大きくなると (数百ビットを超えて)、1<<L
O(lg n) 操作になります。
def clearaltbits(v):
if not v:
return 0
L, R = 16, 0
# Find an upper bound on # bits
while (-1<<L) & v:
R, L = L, 2*L
# Binary search for top bit #
while not (-1<<L) & v:
m = (L+R)/2
if (-1<<m) & v:
R = m
else:
L = m
if L==R+1: break
print bin(v),'has',len(bin(v))-2,'bits.'
# Make big-enough alternate-bits mask
k, b = 0b0101010101010101, 16
while not (-1<<L) & k:
k = (k<<b)|k
b += b
if L & 1:
k = k<<1
k = k & ((1<<L)-1)
print bin(k^v),'fin'
clearaltbits(3**3)
clearaltbits(5**6)
clearaltbits(7**17)
clearaltbits(13**19)
4 つの関数呼び出しからの出力を以下に示します。
0b11011 has 5 bits.
0b10001 fin
0b11110100001001 has 14 bits.
0b10100001011100 fin
0b110100111001001110000011001001100110111010000111 has 48 bits.
0b100001101100011011010110011100110011101111010010 fin
0b10011110100000000111000001101101000001011000100011000010010000111010101 has 71 bits.
0b11001011110101010010010100111000010100001101110110010111000101101111111 fin