Bit Manipulation - HackerEarth
Bit Manipulation - HackerEarth
Bit Manipulation - HackerEarth
Working on bytes, or data types comprising of bytes like ints, oats, doubles or even data structures which stores large amount of bytes is normal
for a programmer. In some cases, a programmer needs to go beyond this - that is to say that in a deeper level where the importance of bits is
realized.
Operations with bits are used in Data compression (data is compressed by converting it from one representation to another, to reduce the space)
,Exclusive-Or Encryption (an algorithm to encrypt the data for safety issues). In order to encode, decode or compress les we have to extract the
data at bit level. Bitwise Operations are faster and closer to the system and sometimes optimize the program to a good level.
We all know that 1 byte comprises of 8 bits and any integer or character can be represented using bits in computers, which we call its binary
form(contains only 1 or 0) or in its base 2 form.
Example:
1) 14 = {1110 }2
= 1 * 23 + 1 * 22 + 1 * 21 + 0 * 20
= 14.
2) 20 = {10100 }2
= 1 * 24 + 0 * 23 + 1 * 22 + 0 * 21 + 0 * 20
= 20.
For characters, we use ASCII representation, which are in the form of integers which again can be represented using bits as explained above.
Bitwise Operators:
There are di erent bitwise operations used in the bit manipulation. These bit operations operate on the individual bits of the bit patterns. Bit
operations are fast and can be used in optimizing time complexity. Some common bit operators are:
NOT ( ~ ): Bitwise NOT is an unary operator that ips the bits of the number i.e., if the ith bit is 0, it will change it to 1 and vice versa. Bitwise NOT
is nothing but simply the ones complement of a number. Lets take an example.
N = 5 = (101)2
~N = ~5 = ~(101)2 = (010)2 = 2
AND ( & ): Bitwise AND is a binary operator that operates on two equal-length bit patterns. If both bits in the compared position of the bit patterns
are 1, the bit in the resulting bit pattern is 1, otherwise 0.
Left Shift ( << ): Left shift operator is a unary operator which shift the some number of bits, in the given bit pattern, to the left and append 0 at the
end. Left shift is equivalent to multiplying the bit pattern with 2k ( if we are shifting k bits ).
1 << 1 = 2 = 21
1 << 2 = 4 = 22 1 << 3 = 8 = 23
1 << 4 = 16 = 24
1 << n = 2n
Right Shift ( >> ): Right shift operator is a unary operator which shift the some number of bits, in the given bit pattern, to the right and append 1 at
the end. Right shift is equivalent to dividing the bit pattern with 2k ( if we are shifting k bits ).
4 >> 1 = 2
6 >> 1 = 3
5 >> 1 = 2
16 >> 4 = 1
Bitwise operators are good for saving space and sometimes to cleverly remove dependencies.
Note: All left and right side taken in this article, are taken with reference to the reader.
Lets discuss some algorithms based on bitwise operations:
1) How to check if a given number is a power of 2 ?
Consider a number N and you need to nd if N is a power of 2. Simple solution to this problem is to repeated divide N by 2 if N is even. If we end
up with a 1 then N is power of 2, otherwise not. There are a special case also. If N = 0 then it is not a power of 2. Lets code it.
Implementation:
bool isPowerOfTwo(int x)
{
if(x == 0)
return false;
else
{
while(x % 2 == 0) x /= 2;
return (x == 1);
}
}
Above function will return true if x is a power of 2, otherwise false.
It might not seem obvious with these examples, but binary representation of (x-1) can be obtained by simply ipping all the bits to the right of
rightmost 1 in x and also including the rightmost 1.
Now think about x & (x-1). x & (x-1) will have all the bits equal to the x except for the rightmost 1 in x.
Let, x = 4 = (100)2
x - 1 = 3 = (011)2
x & (x-1) = 4 & 3 = (100)2 & (011)2 = (000)2
Let, x = 6 = (110)2
x - 1 = 5 = (101)2
x & (x-1) = 6 & 5 = (110)2 & (101)2 = (100)2
Properties for numbers which are powers of 2, is that they have one and only one bit set in their binary representation. If the number is neither
zero nor a power of two, it will have 1 in more than one place. So if x is a power of 2 then x & (x-1) will be 0.
Implementation:
bool isPowerOfTwo(int x)
{
// x will check if x == 0 and !(x & (x - 1)) will check if x is a power of 2 or not
return (x && !(x & (x - 1)));
}
2) Count the number of ones in the binary representation of the given number.
The basic approach to evaluate the binary form of a number is to traverse on it and count the number of ones. But this approach takes log2N of
time in every case.
Why log2N ?
As to get a number in its binary form, we have to divide it by 2, until it gets 0, which will take log2N of time.
With bitwise operations, we can use an algorithm whose running time depends on the number of ones present in the binary form of the given
number. This algorithm is much better, as it will reach to logN, only in its worst case.
int count_one (int n)
{
while( n )
{
n = n&(n-1);
count++;
}
return count;
}
Why this algorithm works ?
As explained in the previous algorithm, the relationship between the bits of x and x-1. So as in x-1, the rightmost 1 and bits right to it are ipped,
then by performing x&(x-1), and storing it in x, will reduce x to a number containing number of ones(in its binary form) less than the previous state
of x, thus increasing the value of count in each iteration.
Example:
n = 23 = {10111}2 .
1. Initially, count = 0.
2. Now, n will change to n&(n-1). As n-1 = 22 = {10110}2 , then n&(n-1) will be {101112 & {10110}2, which will be {10110}2 which is equal to 22.
Therefore n will
3. As n-1 = 21 =
count to 2.
4. As n-1 = 19 =
count to 3.
5. As n-1 = 15 =
count to 4.
6. As n = 0, the the loop will terminate and gives the result as 4.
Complexity: O(K), where K is the number of ones present in the binary form of the given number.
3) Check if the ith bit is set in the binary form of the given number.
To check if the ith bit is set or not (1 or not), we can use AND operator. How?
Lets say we have a number N, and to check whether its ith bit is set or not, we can AND it with the number 2i . The binary form of 2i contains only
ith bit as set (or 1), else every bit is 0 there. When we will AND it with N, and if the ith bit of N is set, then it will return a non zero number (2i to be
speci c), else 0 will be returned.
Using Left shift operator, we can write 2i as 1 << i . Therefore:
bool check (int
{
if( N & (1
return
else
return
}
N)
<< i) )
true;
false;
Example:
Lets say N = 20 = {10100}2. Now lets check if its 2nd bit is set or not(starting from 0). For that, we have to AND it with 22 = 1<<2 = {100}2 .
{10100} & {100} = {100} = 22 = 4(non-zero number), which means its 2nd bit is set.
4) How to generate all the possible subsets of a set ?
A big advantage of bit manipulation is that it can help to iterate over all the subsets of an N-element set. As we all know there are 2N possible
subsets of any given set with N elements. What if we represent each element in a subset with a bit. A bit can be either 0 or 1, thus we can use this
to denote whether the corresponding element belongs to this given subset or not. So each bit pattern will represent a subset.
Consider a set A of 3 elements.
A = {a, b, c}
Now, we need 3 bits, one bit for each element. 1 represent that the corresponding element is present in the subset, whereas 0 represent the
corresponding element is not in the subset. Lets write all the possible combination of these 3 bits.
0 = (000)2 = {}
1 = (001)2 = {c}
2 = (010)2 = {b}
3 = (011)2 = {b, c}
4 = (100)2 = {a}
5 = (101)2 = {a, c}
6 = (110)2 = {a, b}
7 = (111)2 = {a, b, c}
Pseudo Code:
possibleSubsets(A, N):
for i = 0 to 2^N:
for j = 0 to N:
if jth bit is set in i:
print A[j]
print \n
Implementation:
void possibleSubsets(char A[], int N)
{
for(int i = 0;i < (1 << N); ++i)
{
for(int j = 0;j < N;++j)
if(i & (1 << j))
cout << A[j] << ;
cout << endl;
}
}
5) Find the largest power of 2 (most signi cant bit in binary form), which is less than or equal to the given number N.
Idea: Change all the bits which are at the right side of the most signi cant digit, to 1.
Property: As we know that when all the bits of a number N are 1, then N must be equal to the 2i -1 , where i is the number of bits in N.
Example:
This property can be used to nd the largest power of 2 less than or equal to N. How?
If we somehow, change all the bits which are at right side of the most signi cant bit of N to 1, then the number will become x + (x-1) = 2 * x -1 ,
where x is the required answer.
Example:
Lets say N = 21 = {10101}, here most signi cant bit is the 4th one. (counting from 0th digit) and so the answer should be 16.
So lets change all the right side bits of the most signi cant bit to 1. Now the number changes to
{11111} = 31 = 2 * 16 -1 = Y (lets say).
Now the required answer is (Y+1)>>1 or (Y+1)/2.
Now the question arises here is how can we change all right side bits of most signi cant bit to 1?
Lets take the N as 16 bit integer and binary form of N is {1000000000000000}.
Here we have to change all the right side bits to 1.
Initially we will copy that most signi cant bit to its adjacent right side by:
N = N | (N>>1).
As you can see, in above diagram, after performing the operation, rightmost bit has been copied to its adjacent place.
Now we will copy the 2 rightmost set bits to their adjacent right side.
N = N | (N>>2).
Now we will copy the 4 rightmost set bit to their adjacent right side.
N = N | (N>>4)
Now we will copy these 8 rightmost set bits to their adjacent right side.
N = N| (N>>8)
Now all the right side bits of the most signi cant set bit has been changed to 1 .This is how we can change right side bits. This explanation is for 16
(1 << n) will return a number with only nth bit set. So if we OR it with x it will set the nth bit of x.
x = 10 = (1010)2 n = 2
1 << n = (0100)2
Ankit Luthra
7 months ago
what will be the complexity of implementation of largest power of 2 <= given number N explained above
Reply
Message
Permalink
Prateek Garg
Assuming all the bit wise operations as constant time operations (as they are nearly equal to constant), the time complexity of this algorithm can
also be taken as constant.
Reply
Message
Vignesh Mahalingam
Permalink
7 months ago
Message
MD ASAD RUB
Permalink
7 months ago
simple..brilliant..awesome!!
Reply
Message
Nitin Gaikwad
Permalink
7 months ago
Nice...
Reply
Message
Permalink
SHIVA SURYA
7 months ago
Message
Permalink
7 months ago
Small typo mistake in Left Shift ( << ) section :it is written .............1 << n = 2n
Corrected one is .... 1 << n = 2^n(2 power n)
Reply
Message
Permalink
Prateek Garg
Thanks. It is xed.
Reply
Message
Permalink
competitivecoder
7 months ago
@Prateek Garg Do we have some sample problems here at hackerearth.Can you suggest some.except the past codemonk series problem
Reply
Message
Permalink
Prateek Garg
https://www.hackerearth.com/problem/algorithm/aaryan-subsequences-and-great-xor/
https://www.hackerearth.com/problem/algorithm/subset-xor-4/
https://www.hackerearth.com/problem/algorithm/power-of-two-4/
You can start with some easy problems :) .
Reply
Message
Permalink
competitivecoder
7 months ago
Sangh priya
Message
Permalink
7 months ago
superbbbb ...........
Reply
Message
vinayak kothari
Permalink
7 months ago
Message
Permalink
Shyam Singh
7 months ago
A humble request:
I guess "leftmost" should be replaced by "rightmost" in many sentences in this tutorial. New Coders won't get confused.
Reply
Message
Dynamo
Permalink
7 months ago
Right.
Reply
Message
Prateek Garg
Permalink
Author 7 months ago
Yes, it was correct but not clear in some areas. It is xed. Thanks for pointing it out :)
Reply
Dynamo
Message
Permalink
7 months ago
Message
Saeed Reza
Permalink
7 months ago
can you tell how to improvise the code to print only the contiguous subsets? like if a=[1,2,3] subsets are (1),(2),(3),(1,2),(2,3),(1,2,3)....the set(1,3) will not
be included..anyone ?
Reply
Message
Permalink
Vatsal Sharma
Message
Permalink
Roshan Choudhary
5 days ago
This is for subsets and not subarrays...(1,3) is a subarray of the array (1,2,3)
Reply
Message
Satyendra Singh
Permalink
7 months ago
I am new to the programming but these articles are awesome! Can any one tell me if i can download these!
Reply
Message
Permalink
Shreyas Krishna
7 months ago
Message
Permalink
Prateek Garg
yes, it is .
Reply
Message
Hitesh Kalwani
Permalink
7 months ago
Message
Syed Shibli
Permalink
7 months ago
owsome
Reply
Message
Permalink
Vignesh Mahalingam
7 months ago
In " nding the largest power of two"'s implementation's 1st comment line: "//changing all left side bits to 1" is it correct?? Explain please.
Reply
Message
Permalink
Prateek Garg
Message
Shubhankar Dimri
Permalink
7 months ago
Message
Permalink
Prateek Garg
Actually here it is shown only for limited bits, but in system it ips all the bits(32 bits in this case) including the sign bit, that's why the answer is
di erent in both the cases.
Reply
Message
Permalink
Shubhankar Dimri
7 months ago
okay thanks for the clari cation but it will be great if you can make me understand at binary level I never got how (tilde) 5= -6? if all 32 bits are
ipped then isn't the result must be a much bigger negative no?
Reply
Message
Permalink
Message
abhinav vinci
Permalink
7 months ago
Message
Nitesh Singh
Permalink
7 months ago
x & (-x) : Returns the rightmost 1 in binary representation of x ? I am not able to understand ?
eg. 12 = (1100)
-12 =(0100)
(12)&(-12) = (0100) = 4
but the rightmost one is at 3rd positon
Reply
Message
Permalink
Prateek Garg
Here indexing is from 0, so 1 is at 2nd position, which is 2^2 = 4. It returns the value 2^x, where x is the index of rightmost one.
Reply
Message
Naman Ahuja
Permalink
4 months ago
:P
Reply
Message
Nishant Gupta
Permalink
4 months ago
Second That!!
Reply
Abhinav Jha
Message
Permalink
7 months ago
Man this is seriously awesome. I am poor with bit manipulation and needed some good starting material. CodeMonk <3
Reply
As
Message
Permalink
7 months ago
Message
vinayak kothari
Permalink
6 months ago
can anyone give the link from where to study bit mask + dynamic programming
Reply
Message
Permalink
Aj
5 months ago
Message
Permalink
Shubham Aggarwal
5 months ago
Message
Permalink
2 months ago
Applaudable work!!!
Reply
Message
bhargav patel
Permalink
2 months ago
Message
Permalink
a month ago
in right shift operator 2^k should be written and replacement should be done by 0(not by 1 as given)
Reply
Message
Permalink
a month ago
Message
ankur aggarwal
Permalink
a month ago
Message
Ishpreet Singh
Permalink
Edited a month ago
Message
Jason Adams
Permalink
23 days ago
It might not seem obvious with these examples, but binary representation of (x-1) can be obtained by simply ipping all the bits to the right of
rightmost 1 in x and also including the rightmost 1."
Which is the rightmost 1 here? is it the last bit? so for 4 the rightmost 1 will be 0, and for 3 it's 1? Also what do you mean by the "right of the rightmost
1?"
Thanks!
Reply
Message
Permalink
SAURABH AGARWAL
19 days ago
Hey!
The rightmost 1 means , when we start traversing from right the 1 which encountered rst. Like it is the third bit from right in case of 4 and
second bit from right in case of 6.
Reply
Message
SAURABH AGARWAL
Permalink
19 days ago
Message
Permalink
Abhishek Anand
6 days ago
jst quoting ur words "The rightmost 1 means , when we start traversing from right the 1 which encountered rst......"
so if x=3[0011] then x-1=2[0010]......as the rightmost 1 encountered here is at the 0th posn in 3. HOpe m clear ! !
Reply
Message
Permalink