動態

詳情 返回 返回

lintcode179:更新二進制位 - 動態 詳情

lintcode題目鏈接:更新二進制位

描述
給出兩個32位的整數\( N \)和\( M \),以及兩個二進制位的位置\( i \)和\( j \)。寫一個方法來使得N中的第\( i \)到\( j \)位等於\( M \)(\( M \)會是\( N \)中從第\( i \)位開始到第\( j \)位的子串)

在該函數裏給出的\( N \)和\( M \)都是十進制位,同時返回的答案也應該是十進制位
保證從\( i \)到\( j \)的二進制可以完全覆蓋\( M \)。例如,如果\( M=10011 \),那麼可以保證在\( i \)和\( j \)之間至少有5位。 類似\( j=3 \)和\( i=2 \)不會出現,因為\( M \)無法完全覆蓋二進制的第二位和第三位。

樣例
樣例1:

輸入: N=(10000000000)2 M=(10101)2 i=2 j=6
輸出: N=(10001010100)2

樣例 2:

輸入: N=(10000000000)2 M=(11111)2 i=2 j=6
輸出: N=(10001111100)2

解答:
吐槽:純二進制位運算。

整體思路:
假設\( n = 1110101110, m = 10101, i = 2, j = 6 \),
我們通過將\( n \)和\( m \)的二進制轉換成以下形式,來實現目標,為了方便理解,我用_分隔。

n1 = 111_00000_10
m1 = 000_10101_00

簡單來説,就是把中間的\( j-i+1 \)位變成\( 0 \),然後和 (左移\( i \)位的\( m \)) 做"或"運算。

詳細步驟:

  1. 將\( -1 \) 左動 \( j+1 \)位 , \(-1 = 1111...111 \), 一共32個1, 左移後會在右側多出\( j+1 \)個\( 0 \)
  2. 然後將上面的數字, 再 加上 \( 2^i - 1 \), 就是變成111..1110000011, 相當於再最右側的\( i \)位上全變成\( 1 \)
  3. 把上面的數 和 \( n \) 做“與”運算,可以將 \( n \)中間的 \( j - i + 1 \)位都變成 0 , 就實現了上面代碼框中的\( n1\) , 原理: 任何二進制數與1做“與“運算都等於其自身, 任何二進制數與0做“與“運算都等於0。
  4. 將\( m \)左移動\( i \)位,變成上面代碼框中的\( m1 \)
  5. 將\( n1 \)和\( m1 \)二者做“或運算”, 原理: 任何二進制數與0做“或”運算都等於其自身。
  6. 注意坑:如果 \( j=31 \), 第1步中會導致錯亂,因為一個數字左移\( 32 \)位不變,所以需要單獨判斷一下。
public class Solution {
    public int updateBits(int n, int m, int i, int j) {
        int x = j<31? ((-1) << (j+1)) : 0;  // 排坑的代碼
        return (n & ( x + ((1<<i) - 1))) | (m << i);
    }
}

Add a new 評論

Some HTML is okay.