2015年8月18日星期二

Lintcode: Update Bits


Way 1: single bit set
http://www.catonmat.net/blog/low-level-bit-hacks-you-absolutely-must-know/
Check the bit of M is 1 or 0, if 1, set the corresponding bit of M as 1, else, set 0.
Time: O(j - i) , j - i < 32, so it can be regarded as O(1)
Space: O(1)


class Solution {
public:
    /**
     *@param n, m: Two integer
     *@param i, j: Two bit positions
     *return: An integer
     */
    int updateBits(int n, int m, int i, int j) {
        // write your code here
        //int mbit = 0;
        for(; i <= j; i++){
            if(m & 1) n = n | (1<<i);
            else n = n & ~(1<<i);
            m = m>>1;
        }
        return n;
    }
};

Way 2: several bits set together
First, we need a mask, which is 0 from i to j, and 1 for other bits;
Then N & mask, set bits from i to j as 0;
Now we bitwise shift left m by i bits
At last, just bitwise or (N & mask) and shifted m. (set 1)

Another version, the mask is 1 from i to j, and 0 for other bits;
Then N or mask, set bits from i to j as 1;
Now we bitwise shift left m by ibits
At last, just bitwise & (N | mask) and shifted m. (set 0)

The key is how to get mask?
We can easily get the left part of mask by left shift. However, we cannot directly use right shift the same way as we get right part. Since for signed int, the logical shift and arithmetic shift works differently.
http://blog.csdn.net/hengshan/article/details/6440549(explain how left and right shift works)
From the paragraph above, we know that the logical shift is caused by signed bit.
In this problem, bits >= i will be set to 0, however, bit <= 31 for input.
So for right part, bits from i to 31 will be  zero. So the bit[31] is always 0. Which means the signed bit of right part is always 0. Then I can use INT_MAX as the initial right part value than just shift right, which will only add 0 from the left side.

Time: O(1)
Space: O(1)

my version(both left and right shift):

class Solution {
public:
    /**
     *@param n, m: Two integer
     *@param i, j: Two bit positions
     *return: An integer
     */
    int updateBits(int n, int m, int i, int j) {
        // write your code here
        
        int left = ~0 << (j + 1) ;
        if(j >= 31) left = 0;
        //for signed int, left shift is logical shift;
        //           while right shift is arithmetic shift.
        // so we cannot directly use right shift to get mask;
        //int right = ~0 >> (32 - i);
        int right = INT_MAX;
        right = right >> (31 - i);
        int mask = left | right;
        return m<<i | (mask & n);
    }
};


Common version: ( only use left shift)
The right part in an Integer than from 31 to i bit is zero, and from i - 1 to 0 bit is 1
Beside right shift INT_MAX, we can also left shift 1 to i bit, then minus 1.
http://algorithm.yuanbin.me/math_and_bit_manipulation/update_bits.html
Time: O(1)
Space: O(1)


class Solution {
public:
    /**
     *@param n, m: Two integer
     *@param i, j: Two bit positions
     *return: An integer
     */
    int updateBits(int n, int m, int i, int j) {
        // write your code here
        int left = ~0 << (j + 1);
        if( j == 31) left = 0;
        int right = (1 << i) - 1;//Don't forget parenthesis
        int mask = left | right;
        return (n & mask) | (m<<i);
    }
};

KEY: 0 | x = x


没有评论:

发表评论