[英]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.