1. 程式人生 > 實用技巧 >LeetCode201. 數字範圍按位與

LeetCode201. 數字範圍按位與

暴力做法是,列舉從m~n的所有數,因為題目說了資料最大為2147483647,所以可以列舉0~30位,對所有數字的每一位做與運算。

資料比較大的時候這樣做會超時(時間複雜度是O(n))。

參考官方題解,有一個簡單得多的做法。

觀察發現,要對所有數做按位與,只要有一個數的某一位為0,則最後按位與的結果在這一位肯定也是0。

比如9, 10, 11, 12四個數做按位與,低三位各有一個數在那個位為0,因此最終按位與的結果在低三位肯定也是0,只有倒數第四位,四個數都是1,因此按位與的結果是1,所以最終所有數按位與的結果在倒數第四位也是1。
更高位的數就都是0了,沒什麼好說的。

可以發現,按位與的結果就是所有數的二進位制公共字首,低位全部是0.比如上面例子中公共字首是倒數第四位的1,低三位都是0,所以結果就是1 0 0 0,也就是8.

因為從m到n,每一個數是逐漸加一的,每次加一,會從低位開始變化,所以所有數的公共字首,就是左右端點m和n的公共字首,所以我們只需要找到m和n的公共字首,然後低位都補上0就可以了。

找公共字首的方法可以用右移操作,同時右移m和n直到兩個數相等,當然要記錄位移的次數,然後把m(或n,此時m和n兩個數已經相等了,就是他們的公共字首)左移他們的位移次數(也就相當於低位補0)就是最後的答案了。

比如上圖,9和12右移3次之後相等了,也就是找到公共字首1,然後把1左移三次,就是9~12之間所有的數的按位與的結果了。

程式碼如下:

class Solution {
public:
    int rangeBitwiseAnd(int m, int n) {
        int shift = 0;                  //記錄右移次數
        while(m < n) {                  //m和n同時右移,直到兩個數相等(也就是找到了公共字首)
            m >>= 1;
            n >>= 1;
            ++shift;
        }
        return m << shift;              //退出while迴圈後,m和n就是公共字首了,左移shift次就是答案
    }
};