问题是如何反转数字的交替位,从LSB
. 目前我正在做的是首先做一个
count = -1
while n:
n >>= 1
count += 1
首先找到最左边的设置位的位置,然后运行一个循环来反转每个交替位:
i = 0
while i <= count:
num ^= 1<<i
i += 2
有没有一个快速破解解决方案而不是这个相当无聊的循环解决方案?当然,解决方案不能对整数的大小做出任何假设。
问题是如何反转数字的交替位,从LSB
. 目前我正在做的是首先做一个
count = -1
while n:
n >>= 1
count += 1
首先找到最左边的设置位的位置,然后运行一个循环来反转每个交替位:
i = 0
while i <= count:
num ^= 1<<i
i += 2
有没有一个快速破解解决方案而不是这个相当无聊的循环解决方案?当然,解决方案不能对整数的大小做出任何假设。
我认为这可能有效:
具有交替掩码的按位 XOR10101010...10
应每隔一位反转。
如果要反转 '0011' 中的交替位,下表显示了结果:
i | m | i XOR m
0 | 0 | 0
0 | 1 | 1
1 | 0 | 1
1 | 1 | 0
在 python 中,XOR 是通过i ^ m
. 当然,您也必须确定掩码的字面值,这取决于您的i
数字的大小。
以前的单线解决方案,
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 加倍(使越来越多的低位清空),直到 L 超过数字 v 中的位数;也就是说,直到(-1<<L)&v
为零。每增加一倍 L,它可以使 R 向上移动。然后程序使用二分查找,反复将 LR 差减半,找到 L=R+1 使得v&(-1<<L) == 0
和v&(-1<<R) > 0
,确定 v 的长度为 L 位。之后,程序将交替位掩码 k 的长度加倍,直到它至少有 L 位长。然后如果 L 是奇数,它将掩码移动一位。(而不是if L & 1: k = k<<1
它可以说k <<= L&1
. 请注意,我将“备用位”解释为从 MSB 正下方的位开始。要始终切换位 0,2,4...,请删除该if L & 1: k = k<<1
行。)然后它通过 &'ing 与(1<<L)-1
(2**L)-1 提取 k 的低 L 位。注意,程序的 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)
四个函数调用的输出如下所示。
0b11011 has 5 bits.
0b10001 fin
0b11110100001001 has 14 bits.
0b10100001011100 fin
0b110100111001001110000011001001100110111010000111 has 48 bits.
0b100001101100011011010110011100110011101111010010 fin
0b10011110100000000111000001101101000001011000100011000010010000111010101 has 71 bits.
0b11001011110101010010010100111000010100001101110110010111000101101111111 fin
扩展 trideceth12 给出的答案 - 这是一个计算和应用掩码的单线:
n ^ sum(2**i for i in range(0, len(bin(n))-2, 2))
...假设您确实想从 LSB 开始,也就是说。
或者,如果您从最重要的设置位开始:
n ^ sum(2**i for i in range(len(bin(n))-3, -1, -2))
这适用于任何长度的正整数:
def invert_alt_bits(n):
m = 1
while True:
n ^= m
m <<= 2
if m > n: break
return n