原題地址
https://leetcode.com/problems/bitwise-and-of-numbers-range/
題目描述
Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all numbers in this range, inclusive.
給出一個區間 [m, n],其中0 <= m <= n <= 2147483647,即m,n都是非負整數,返回這個區間內所有整數的按位與結果,包括m和n在內.
For example, given the range [5, 7], you should return 4.
例如,給出區間 [5, 7],你應該返回4.
5 --- 0000 0101
6 --- 0000 0110
7 --- 0000 0111
_______________
4 --- 0000 0100
解題思路
顯然,暴力解決方法是從m開始直到n求按位與,但很明顯這太慢了,雖然時間複雜度是O(n),但顯然不是一個好的解法.我們可以注意到這樣一點,在數字加1的時候,最低位肯定會從0變成1,或者從1變成0,不管哪樣,兩個數的最低位中勢必有一個0,而一旦出現了一個0,這一位上的按位與結果將永遠爲0.假如在m->n的增加過程中,m的最高位也發生了改變,那麼m之下的所有位都變成過0.那樣的話結果也只能是0了.我們再來看兩個相鄰的數,m,m+1,在+1的時候,改變的位可能是多個,而且改變一定是0->1或者1->0,因此,發生改變的位在求AND操作後結果一定是0,因此只有那些沒有改變的位才能在AND結果之後保留下來,於是對於m和m+1我們只要找到從最高位開始完全相同的位.同樣對於m+1和m+2也是如此.但是如果我們真的按照這個邏輯來的話就跟暴力解法一樣了.我們可以發現,對於m和n,找到他們從最高位開始完全相同的位,就是我們需要的結果.這也不難理解,m和n假如在最高位到x位之間的二進制位完全相同,這就說明在遞增的過程中+1的操作永遠沒有改變過這些位,而相反第x-1到最後一位都至少改變過一次,而改變一定是0->1或者1->0,就是說在着m-n+1個操作數中至少有一個的第i位(i>=0 && i<=x-1)爲0.因此,第x-1位之下全都爲0,m和n從最高位開始的連續相同部分就是我們要的結果.
算法
- 偏移量offset = 0
- 當m,n都不爲0時執行循環,進入3
- 如果m==n,返回m << offset,否則4
- m,n均右移一位,offset加1,進入3
代碼
int rangeBitwiseAnd(int m, int n) {
int offset = 0;
while (m && n) {
if (m == n) return m << offset;
m >>= 1;
n >>= 1;
++offset;
}
return 0;
}
完整代碼 https://github.com/Orange1991/leetcode/blob/master/201/c/main.c
2015/8/6