Bit Manipulation
Overviewβ
We all know that information is stored in the form of bits in computer memory, which means directly manipulating these bits will yield faster results than performing computation on ordinary data.
Binary uses only and to represent a number in a base-2 number system. The series of 0 and 1 are called bits. If the bit is , then this bit is set. We read binary number from right to left. For example, the binary representation of number is which can be calculated by summing up all the set bit: . Bit Manipulation utilises different bitwise operations to manipulate bits.
Bitwise Operatorsβ
X | Y | X & Y | X | Y | X ^ Y | ~ X |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 1 |
0 | 1 | 0 | 1 | 1 | 1 |
1 | 0 | 0 | 1 | 1 | 0 |
1 | 1 | 1 | 1 | 0 | 0 |
AND (&) Operatorβ
& takes two bit integers to compare. If the bits are both , then the resulting bit is , else .
For example, & because only the second bits from the right are both .
Usage #1: Check if the rightmost bit is setβ
Let's say is which is . If we execute & , i.e. & , the result is because only the rightmost bits are both 1 and other bits would return 0.
Usage #2: Check if the i-th bit is setβ
Let's say is which is . How to check if the 2-nd, 3-rd, or 4-th bit is set? Using the same idea, the mask would be , , respectively. And you may notice that the mask is always a power of 2. A common way to do it is to use left shift operator (which will be discussed below), i.e. & where is the i-th bit to be checked.
Usage #3: Remove the rightmost set bitβ
We can use & to remove the rightmost set bit.
n n n - 1 n & (n - 1)
-- ---- ---- -------
0 0000 0111 0000
1 0001 0000 0000
2 0010 0001 0000
3 0011 0010 0010
4 0100 0011 0000
5 0101 0100 0100
6 0110 0101 0100
7 0111 0110 0110
8 1000 0111 0000
9 1001 1000 1000
10 1010 1001 1000
11 1011 1010 1010
12 1100 1011 1000
13 1101 1100 1100
14 1110 1101 1100
15 1111 1110 1110
Example #1: 0231 - Power of Two (Easy)β
We know that a power of 2 is a positive number and only has one bit set. We can use & to see the result is 0 or not to determine if the target value is a power of 2 or not.
In short, & never have a 1 bit in the same place.
For example, 1000 (8), and 0111(7) - never have 1 bit in the same place for Power of Two
class Solution {
public:
bool isPowerOfTwo(int n) {
// 1. check if it is a positive number
// 2. check the value is 0 after removing the rightmost bit
return n > 0 && !(n & (n - 1));
}
};
Example #2: 0191 - Number of 1 Bitsβ
Instead of checking the bits one by one, we can use & to jump to the next set bit.
class Solution {
public:
int hammingWeight(uint32_t n) {
int ans = 0;
for (; n; n = n & (n - 1)) ans++;
return ans;
}
};
OR (|) Operatorβ
takes two bit integers to compare. If either bits are , then the resulting bit is , else .
For example,