1. 程式人生 > >[LeetCode] Bitwise AND of Numbers Range 數字範圍位相與

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

For example, given the range [5, 7], you should return 4.

Credits:
Special thanks to @amrsaqr for adding this problem and creating all test cases.

101  110  111

相與後的結果為100,仔細觀察我們可以得出,最後的數是該數字範圍內所有的數的左邊共同的部分,如果上面那個例子不太明顯,我們再來看一個範圍[26, 30],它們的二進位制如下:

11010  11011  11100  11101  11110

發現了規律後,我們只要寫程式碼找到左邊公共的部分即可,我們可以從建立一個32位都是1的mask,然後每次向左移一位,比較m和n是否相同,不同再繼續左移一位,直至相同,然後把m和mask相與就是最終結果,程式碼如下:

解法一:

class Solution {
public:
    int rangeBitwiseAnd(int m, int n) {
        int d = INT_MAX;
        while ((m & d) != (n & d)) {
            d 
<<= 1; } return m & d; } };

此題還有另一種解法,不需要用mask,直接平移m和n,每次向右移一位,直到m和n相等,記錄下所有平移的次數i,然後再把m左移i位即為最終結果,程式碼如下:

解法二:

class Solution {
public:
    int rangeBitwiseAnd(int m, int n) {
        int i = 0;
        while (m != n) {
            m >>= 1;
            n 
>>= 1; ++i; } return (m << i); } };

下面這種方法有點叼,就一行搞定了,通過遞迴來做的,如果n大於m,那麼就對m和n分別除以2,並且呼叫遞迴函式,對結果再乘以2,一定要乘回來,不然就不對了,就舉一個最簡單的例子,m = 10, n = 11,注意這裡是二進位制表示的,然後各自除以2,都變成了1,呼叫遞迴返回1,這時候要乘以2,才能變回10,參見程式碼如下:

解法三:

class Solution {
public:
    int rangeBitwiseAnd(int m, int n) {
        return (n > m) ? (rangeBitwiseAnd(m / 2, n / 2) << 1) : m;
    }
};

下面這種方法也不錯,也很簡單,如果m小於n就進行迴圈,n與上n-1,那麼為什麼要這樣與呢,舉個簡單的例子唄,110與上(110-1),得到100,這不就相當於去掉最低位的1麼,n就這樣每次去掉最低位的1,如果小於等於m了,返回此時的n即可,參見程式碼如下:

解法四:

class Solution {
public:
    int rangeBitwiseAnd(int m, int n) {
        while (m < n) n &= (n - 1);
        return n;
    }
};

參考資料: