[英]Fast bit counting in range
我需要找到解决这个问题的算法:
找到范围[x,y]中数字中所有正位的总和。
警告:x和y可能非常大(从1到10 ^ 20)。
感谢帮助。
查看确定模式的具体示例可能具有指导意义。 例如,20到25.这是他们的二进制表示:
20: 10100
21: 10101
22: 10110
23: 10111
24: 11000
25: 11001
按列查看,很明显最右边的列总是在0和1之间交替。从中我们可以得出结论,如果你的范围中有N个数字而N是偶数,那么最右边的列中有N / 2个比特。 现在忽略最右边的列并尝试在剩余的位中识别模式。
1010
1010
1011
1011
1100
1100
列表中的每个数字只重复一次。 转换为十进制,我们看到这些数字是1010 = 10
1011 = 11
1100 = 12
。 使用这两个观察结果,我们可以得出结论: bitsInRange(20, 25) = (27 - 20 - 1) + 2*bitsInRange(10,12)
。 我们识别的两种模式对于任何偶数起始编号和奇数结束编号都是正确的,因此公式可以推广到:
bitsInRange(X,Y) =
if X is even and Y is odd:
(Y - X - 1) + 2*bitsInRange(X/2, (Y-1)/2)
但是如果我们有一个奇数的起始数字,或者一个偶数的结束数字怎么办? 上述公式对那些公式不起作用,因为我们确定的两种模式对于那些类型的数字并不完全相同。 您可以尝试为偶数和奇数的每种可能组合编写单独的公式,但这种方式是危险的并且充满了Fencepost错误 。 如果您利用这些关键属性,您将获得更轻松的时间:
bitsInRange(X, Y) = bitsInRange(X, Y-1) + numBits(Y)
bitsInRange(X, Y) = bitsInRange(X+1, Y) + numBits(X)
...其中numBits
给出单个数字中1
位的数量。
现在我们可以为偶数和奇数范围的每种可能组合编写递归公式。 (顺便说一下,我们还需要一个基础案例)
function bitsInRange(X,Y):
if X == Y:
return numBits(X)
if X is odd:
return bitsInRange(X+1, Y) + numBits(X)
if Y is even:
return bitsInRange(X, Y-1) + numBits(Y)
return (Y - X - 1) + 2*bitsInRange(X/2, (Y-1)/2)
因为最后的案例将问题空间减半,而所有其他案例都将问题迅速转化为最终案例,整个公式具有对数复杂度。 如果你试图获得像[1,10 ^ 20]这样的巨大范围内的比特,这是很好的。 即使对于这样的大数字, bitsInRange
也只会运行大约200次左右。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.