LeetCode201. 數字範圍按位與
阿新 • • 發佈:2020-08-04
暴力做法是,列舉從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次就是答案 } };