標籤:
在Java位元運算總結-leetcode題目博文中總結了Java提供的按位元運算操作符,今天又碰到LeetCode中一道按位操作的題目
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.
題意:
給出m和n,將m到n之間所有的數字與一遍返回結果(包括m和n)
解題思路:
題目乍一看很簡單嘛,迴圈遍曆m到n按位與一遍返回結果就完了啊,但是將這種解法放入LeetCode會發現逾時,那麼就需要我們去總結規律。
例如題目給出的5,6,7二進位
0101 0110 0111
通過觀察我們會發現我們只要看數位高位即可,後面的數字會相互約掉
再比如
011000 0110001 0110010 0110011
我們發現貌似只要查看所有數位高k位即可
再比如
01100 01101 01110 01111 10000
我們比較發現如果m和n的位元不相同就會返回0
規律如下:
給出m和n,求出m和n相同的高k位(這裡m和n為整型變數,那麼按照32位來看待,前面的0也算作高位比較),那麼保留高k為其餘位置0即為最後結果。
代碼如下:
一開始我選擇從低位遍曆,記錄需要捨棄的低l位
代碼1
1 public int rangeBitwiseAnd(int m, int n) { 2 if (n == m) 3 return m; 4 int h = 0; 5 int l = 0; 6 int mm = m; 7 while (m > 0 || n > 0) { 8 if ((m & 1) == (n & 1)) { 9 m >>= 1;10 n >>= 1;11 ++h;12 }13 else {14 m >>= 1;15 n >>= 1;16 l += h;17 ++l;18 h = 0;19 }20 }21 if(h==0)return 0;22 return mm & (0x7fffffff << l);23 }
通過後查看代碼其實直接從高位開始遍曆到第一個不相同的位停下即可找到高k位,代碼如下
代碼2
1 public int rangeBitwiseAnd2(int m, int n) {2 if(m==n) return m;3 int i;4 for(i = 31;i>0;i--){5 if((m&(1<<i))!=(n&(1<<i)))6 break;7 }8 return m&(~((1<<i+1)-1));9 }
代碼簡潔了很多,也比原來的快了很多
題目再次利用了Java中的移位操作,記錄下做題中遇到的二進位的幾個問題:
1.整數x求-x,從二進位角度看是將x按位取反加1
2.左移正負數都是低位補0,右移正數高位補0負數補1,而如果使用Java無符號右移>>>則正負高位都補0
3.將整數按照二進位整個翻轉可以利用類似歸併排序的分治思想
(1) 整數32為分成16和16先翻轉一下
(2) 再翻轉前16位中的前8位和後8位,再翻轉後16位中的前8位和後8位
。。。以此類推,總共需要Log232 = 5次
代碼如下:
1 public int reverseBit(int n) {2 n = ((n & 0xffff0000) >>> 16) | ((n & 0x0000ffff) << 16);3 n = ((n & 0xff00ff00) >>> 8) | ((n & 0x00ff00ff) << 8);4 n = ((n & 0xf0f0f0f0) >>> 4) | ((n & 0x0f0f0f0f) << 4);5 n = ((n & 0xcccccccc) >>> 2) | ((n & 0x33333333) << 2);6 n = ((n & 0xaaaaaaaa) >>> 1) | ((n & 0x55555555) << 1);7 return n;8 }
注意這裡是將整個32位全部翻轉,相當於32位倒過來看。
舉例,按照4位來看
1110
(1)將前2位和末2位翻轉 10 11
(2)將第一部分對調,第二部分對調得到結果 01 11
Java 位元運算2-LeetCode 201 Bitwise AND of Numbers Range