Skip to content

Commit 41f97dc

Browse files
authored
Merge pull request #86 from shoebxsiddiqui/shoebxsiddiqui-Bitwise-operator.md
Update bitwise-operator.md
2 parents ad3c2a9 + 584fc8f commit 41f97dc

File tree

1 file changed

+387
-0
lines changed

1 file changed

+387
-0
lines changed

lessons/bitwise-operator.md

Lines changed: 387 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,390 @@ order: "10B"
55
section: "Maths for DSA"
66
description: "learn maths required in DSA"
77
---
8+
In this lesson, we are going to learn about the bit-wise operators, and some Bit-manipulation techniques to get optimized solutions. These concepts are very important from competitive programming as well as interviews point of view. Okay, so let's learn these techniques:
9+
In this lesson, we are going to learn about the bit-wise operators, and some Bit-manipulation techniques to get optimized solutions. These concepts are very important from competitive programming as well as interviews point of view. Okay, so let's learn these techniques:
10+
## Bit Manipulation
11+
12+
Bit manipulation is the process of applying logical operations on a sequence of bits, the smallest form of data in a computer, to achieve a required result. Bit manipulation has constant time complexity and process in parallel, meaning it is very efficient on all systems.
13+
14+
Most programming languages will have you work with abstractions, like objects or variables, rather than the bits they represent. However, direct bit manipulation is needed to improve performance and reduce error in certain situations.
15+
16+
Bit manipulation requires a strong knowledge of binary and binary conversion.
17+
18+
Here’s a few examples of tasks that require bit manipulation:
19+
20+
* Low-level device control
21+
* Error detection and correction algorithms
22+
* Data compression
23+
* Encryption algorithms
24+
* Optimization
25+
26+
## Bitwise Manipulation and Coding Interviews
27+
Bit manipulation is also a common topic in coding interviews, especially with FAANG companies. These interviewers expect you to have a basic understanding of bits, fundamental bit operators, and generally understand the thought process behind bit manipulation.
28+
> Having this knowledge demonstrates that you’re a well-rounded developer who understands both the specific tools and the foundation of computer science.
29+
30+
If you’re applying for a role that will work with embedded systems or other low-level systems, you’ll encounter more bit questions. In short, the closer your role is to machine level, the more bit manipulation questions you’ll encounter.
31+
32+
The best way to prepare for bit manipulation questions is to practice using each bitwise operator and brush up on your binary to decimal conversions.
33+
## Bitwise Operators In Java
34+
You are no doubt familiar with the arithmetic operators such as + - * / or %. You are also aware of logical operators such as & or |. Turns out there is another, a slightly less known set of operators, which manipulate numbers on bit level. Internally, every number is stored in a binary format - that is 0 and 1. Bitwise operators are used for performing manipulation of bits of a number. These can be used with any type of integer data types (char, short, int, etc).
35+
36+
These operators can be performed on integer types -
37+
38+
* byte (8 bit)
39+
* short (16 bit)
40+
* int (32 bit)
41+
* long (64 bit), and even
42+
* char (16 bit)
43+
44+
Now let's see its type one by one:
45+
## 1. Unary bitwise complement [~]
46+
This fancy name basically means bit negation. It takes every single bit of the number and flips its value,i.e, ~0 becomes 1 and vice versa. It is the 1's complement of the number. Unary means that it needs just one operand. The operator is `~` and it is just placed before the number:
47+
```java
48+
a = 5 = 0101 (In Binary)
49+
50+
Bitwise Complement Operation of 5
51+
52+
~ 0101
53+
________
54+
1010 = 10 (In decimal)
55+
```
56+
## 2. Bitwise AND [&]
57+
Unlike bitwise complement operator, other bitwise operators need two operands.
58+
59+
A & B means that all the bits of both numbers are compared one by one and the resulting number is calculated based on values of the bits from numbers A and B. Bitwise AND is similar to logical AND in a sense that it results in 1 only when the two compared bits are both equal to 1. Otherwise, it results in 0.
60+
61+
For example: 1010 & 1100 would result in 1000 as the first bit from the left is the only one where both operands contain 1.
62+
```java
63+
a = 5 = 0101 (In Binary)
64+
b = 7 = 0111 (In Binary)
65+
66+
Bitwise AND Operation of 5 and 7
67+
0101
68+
& 0111
69+
________
70+
0101 = 5 (In decimal)
71+
```
72+
## 3. Bitwise OR [ | ]
73+
Bitwise OR results in 1 when at least one of the compared bits is 1 (or both), otherwise it results in 0.
74+
```java
75+
a = 5 = 0101 (In Binary)
76+
b = 7 = 0111 (In Binary)
77+
78+
Bitwise OR Operation of 5 and 7
79+
0101
80+
| 0111
81+
________
82+
0111 = 7 (In decimal)
83+
```
84+
## 4. Bitwise Exclusive OR (XOR) [^]
85+
xclusive OR (XOR) results in 1 only if both the compared bits have a different value, otherwise, it results in 0.
86+
```java
87+
a = 5 = 0101 (In Binary)
88+
b = 7 = 0111 (In Binary)
89+
90+
Bitwise XOR Operation of 5 and 7
91+
0101
92+
^ 0111
93+
________
94+
0010 = 2 (In decimal)
95+
```
96+
|A |B |A AND B |A B |A XOR B |
97+
|-----|----|----------|---------|----------|
98+
|1 |0 |0 |1 |1 |
99+
|0 |1 |0 |1 |1 |
100+
|1 |1 |1 |1 |0 |
101+
|0 |0 |0 |0 |0 |
102+
103+
```java
104+
// Java program to illustrate
105+
// bitwise operators
106+
public class operators {
107+
public static void main(String[] args)
108+
{
109+
// Initial values
110+
int a = 5;
111+
int b = 7;
112+
113+
// bitwise and
114+
// 0101 & 0111=0101 = 5
115+
System.out.println("a&b = " + (a & b));
116+
117+
// bitwise or
118+
// 0101 | 0111=0111 = 7
119+
System.out.println("a|b = " + (a | b));
120+
121+
// bitwise xor
122+
// 0101 ^ 0111=0010 = 2
123+
System.out.println("a^b = " + (a ^ b));
124+
125+
// bitwise not
126+
// ~0101=1010
127+
// will give 2's complement of 1010 = -6
128+
System.out.println("~a = " + ~a);
129+
130+
// can also be combined with
131+
// assignment operator to provide shorthand
132+
// assignment
133+
// a=a&b
134+
a &= b;
135+
System.out.println("a= " + a);
136+
}
137+
}
138+
```
139+
### Output:
140+
```
141+
a&b = 5
142+
a|b = 7
143+
a^b = 2
144+
~a = -6
145+
a= 5
146+
```
147+
## 5. Signed Left Shift [<<]
148+
Signed Left Shift takes two operands. It takes the bit pattern of the first operand and shifts it to the left by the number of places given by the second operand. For example 5 << 3: What happens in this case - Every bit in the binary representation of the integer 5 is shifted by 3 positions to the left. All the places on the left are padded by zeros. That is: `00000101` becomes `00101000`.
149+
150+
You can note that the integer result of 5 << 3 is 40. That shows that shifting a number by one is equivalent to multiplying it by 2, or more generally left shifting a number by n positions is equivalent to multiplication by `2^n`. In this case, it is 5*2^3 = 40.
151+
152+
* Even though you can use shifting of byte, short or char, they are promoted to 32-bit integer before the shifting
153+
* Bit-shift operators never throw an exception
154+
* The right operand (the number of positions to shift) is reduced to modulo 32. That is 5 <<35 is equivalent to 5 << 3.
155+
```java
156+
a = 5 = 0000 0101
157+
b = -10 = 1111 0110
158+
159+
a << 1 = 0000 1010 = 10
160+
a << 2 = 0001 0100 = 20
161+
162+
b << 1 = 1110 1100 = -20
163+
b << 2 = 1101 1000 = -40
164+
```
165+
## 6. Signed Right Shift [>>]
166+
Signed right shift moves all the bits by given number of positions to the right. However, it preserves the sign. Positive numbers remain positive and negative ones remain negative. Similar to left shift, the right shift of n positions is equivalent to division by 2^n. Or division by 2^n -1 in case of odd numbers.
167+
```java
168+
a = 10
169+
a>>1 = 5
170+
171+
Example 2:
172+
a = -10
173+
a>>1 = -5
174+
We preserve the sign bit.
175+
```
176+
## 7. Unsigned Right Shift [>>>]
177+
Unlike the signed shift, the unsigned one does not take sign bits into consideration, it just shifts all the bits to the right and pads the result with zeros from the left. That means that for negative numbers, the result is always positive. Signed and unsigned right shifts have the same result for positive numbers.
178+
```java
179+
a = 10
180+
a>>>1 = 5
181+
182+
a = -10
183+
a>>>1 = 2147483643
184+
DOES NOT preserve the sign bit.
185+
```
186+
This operator shifts the first operand to the specified number of bits to the right. Excess bits shifted off to the right are `discarded`. Zero bits are shifted in from the left. The sign bit becomes 0, so the result is `always non-negative`. Unlike the other bitwise operators, zero-fill right shift returns an unsigned 32-bit integer.
187+
188+
For non-negative numbers, zero-fill right shift and sign-propagating right shift yield the same result. For example, 9 >>> 2 yields 2, the same as 9 >> 2:
189+
## 8. Unsigned Left Shift [<<<]
190+
Unlike unsigned Right Shift, there is no “<<<” operator in Java, because the logical (<<) and arithmetic left-shift (<<<) operations are identical.
191+
```java
192+
9 (base 10): 00000000000000000000000000001001 (base 2)
193+
9 >>> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)
194+
```
195+
However, this is not the case for negative numbers. For example, -9 >>> 2 yields 1073741821, which is different than -9 >> 2 (which yields -3):
196+
```java
197+
-9 (base 10): 11111111111111111111111111110111 (base 2)
198+
-9 >>> 2 (base 10): 00111111111111111111111111111101 (base 2) = 1073741821 (base 10)
199+
```
200+
201+
|Operator |Example |Is equivalent to |
202+
|----------|------------|------------------|
203+
|OR= |x OR= 5 |x = x OR 5 |
204+
|^= |x ^= 5 |x = x ^ 5 |
205+
|&= |x &= 5 |x = x & 5 |
206+
|<<= |x <<= 5 |x = x << 5 |
207+
|>>= |x >>= 5 |x = x >> 5 |
208+
|>>>= |x >>>= 5 |x = x >>> 5 |
209+
210+
```java
211+
// Java program to illustrate
212+
// shift operators
213+
public class operators {
214+
public static void main(String[] args)
215+
{
216+
217+
int a = 5;
218+
int b = -10;
219+
220+
// left shift operator
221+
// 0000 0101<<2 =0001 0100(20)
222+
// similar to 5*(2^2)
223+
System.out.println("a<<2 = " + (a << 2));
224+
225+
// right shift operator
226+
// 0000 0101 >> 2 =0000 0001(1)
227+
// similar to 5/(2^2)
228+
System.out.println("b>>2 = " + (b >> 2));
229+
230+
// unsigned right shift operator
231+
System.out.println("b>>>2 = " + (b >>> 2));
232+
}
233+
}
234+
```
235+
### Output:
236+
```
237+
a<<2 = 20
238+
b>>2 = -3
239+
b>>>2 = 1073741821
240+
```
241+
## Bitwise Tricks And Some Questions
242+
Now, let’s look at a few tricks you can do using bitwise operators.
243+
244+
These are often used as interview questions to check if you’ve reviewed basic bit manipulation and can apply it to day-to-day coding tasks.
245+
### Q1. Check for EVEN / ODD
246+
To check a number is even or odd, we need to look at the number in its binary form first, lets take an eg, 4 ,i.e, `0100`, if we look carefully then we will find out that the 1 present in the number is at `power of 2` position, lets take another example now, 6 ,i.e, `0110`, here both the 1's are at `power of 2` position and now we can conclude that in binary form if the number is at power of 2 position the it is even. Lets check for odd no. now, eg, 5 ,i.e, `0101` here the least significant digit(or `LSD`) is `not` at the `power of 2` position and thus it is odd.
247+
248+
Now, lets look how to solve this,
249+
250+
if we and a number with one then we know we get back that original number, so if we and the last digit with one and if we get 1 then it would be a odd number else it would be even.
251+
```java
252+
if (x & 1 ) == 0
253+
return true;
254+
else
255+
return false;
256+
```
257+
### Q2. Convert characters to Uppercase/Lowercase
258+
This trick tests your knowledge of uppercase and lowercase characters in binary. You can convert any character, `ch`, to the opposite case using `ch ^= 32`.
259+
260+
This is because the binary representation of lowercase and uppercase letters are nearly identical, with only 1 bit of difference.
261+
262+
Using the XOR operation lets us toggle that single bit and swap it to the opposite value, therefore making a lowercase character uppercase or vice versa.
263+
```java
264+
public class Test
265+
{
266+
267+
static int x=32;
268+
269+
// tOGGLE cASE = swaps CAPS to lower
270+
// case and lower case to CAPS
271+
static String toggleCase(char[] a)
272+
{
273+
for (int i=0; i<a.length; i++) {
274+
275+
// Bitwise XOR with 32
276+
a[i]^=32;
277+
}
278+
return new String(a);
279+
}
280+
281+
/* Driver program */
282+
public static void main(String[] args)
283+
{
284+
String str = "CheRrY";
285+
System.out.print("Toggle case: ");
286+
str = toggleCase(str.toCharArray());
287+
System.out.println(str);
288+
289+
System.out.print("Original string: ");
290+
str = toggleCase(str.toCharArray());
291+
System.out.println(str);
292+
}
293+
}
294+
```
295+
### Output:
296+
```
297+
Toggle case: cHErRy
298+
Original string: CheRrY
299+
```
300+
### Q3. Find Number of Setbits
301+
```java
302+
class CountSetBit {
303+
private static int helper(int n) {
304+
int count = 0;
305+
while (n > 0) {
306+
n &= (n - 1);
307+
count++;
308+
}
309+
return count;
310+
}
311+
312+
public static void main(String[] args) {
313+
int number = 125;
314+
System.out.println("SetBit Count is : " + helper(number));
315+
}
316+
}
317+
```
318+
### Output:
319+
```
320+
SetBit Count is : 6
321+
```
322+
323+
In this approach, we count only the set bits. So,
324+
325+
* If a number has 2 set bits, then the while loop runs two times.
326+
* If a number has 4 set bits, then the while loop runs four times.
327+
### Q4. Single Number
328+
You are given an array in which every number appears twice except one number, return that number.
329+
```java
330+
class SingleNumber {
331+
private static int singleNumber(int[] nums) {
332+
int xor = 0;
333+
for (int num : nums) {
334+
xor ^= num;
335+
}
336+
return xor;
337+
}
338+
339+
public static void main(String[] args) {
340+
int[] nums = {4, 1, 2, 9, 1, 4, 2};
341+
System.out.println("Element appearing one time is " + singleNumber(nums));
342+
}
343+
}
344+
```
345+
### Output:
346+
```
347+
Element appearing one time is 9
348+
```
349+
This solution relies on the following logic:
350+
351+
* If we take XOR of zero and some bit, it will return that bit: a ^ 0 = a
352+
* If we take XOR of two same bits, it will return 0: a ^ a = 0
353+
* For n numbers, the below math can be applied: a ^ b ^ a = (a ^ a) ^ b = 0 ^ b = b
354+
355+
Therefore, we can XOR all bits together to find the unique number.
356+
### Q5. Get First Set Bit
357+
```java
358+
class FirstSetBitPosition {
359+
private static int helper(int n) {
360+
if (n == 0) {
361+
return 0;
362+
}
363+
364+
int k = 1;
365+
366+
while (true) {
367+
if ((n & (1 << (k - 1))) == 0) {
368+
k++;
369+
} else {
370+
return k;
371+
}
372+
}
373+
}
374+
375+
public static void main(String[] args) {
376+
System.out.println("First setbit position for number: 18 is -> " + helper(18));
377+
System.out.println("First setbit position for number: 5 is -> " + helper(5));
378+
System.out.println("First setbit position for number: 32 is -> " + helper(32));
379+
}
380+
}
381+
```
382+
### Output:
383+
```
384+
First setbit position for number: 18 is -> 2
385+
First setbit position for number: 5 is -> 1
386+
First setbit position for number: 32 is -> 6
387+
```
388+
The logic of this solution relies on a combination of left shifting and the AND operation.
389+
390+
Essentially, we first check if the rightmost significant bit is the set bet using `bit & 1`. If not, we keep shifting left and checking until we find the bit that makes our AND operation yield 1.
391+
392+
The number of shifts is tracked by our pointer, k. Once we do find the set bit, we return k as our answer.
393+
394+
---

0 commit comments

Comments
 (0)