190. Reverse Bits
Problem Description
You are given a 32-bit signed integer n
. Your task is to reverse all the bits in this integer and return the resulting value.
When reversing bits, the bit at position 0 (rightmost/least significant bit) should move to position 31 (leftmost/most significant bit), the bit at position 1 should move to position 30, and so on. Each bit maintains its value (0 or 1) but changes its position to create a mirror image of the original bit pattern.
For example, if you have the binary representation 00000010100101000001111010011100
, after reversing the bits, you would get 00111001011110000010100101000000
.
The solution works by iterating through all 32 bits of the input number. For each iteration i
:
- Extract the least significant bit of
n
using(n & 1)
- Place this bit at position
(31 - i)
in the result using left shift:(n & 1) << (31 - i)
- Combine it with the result using the OR operation:
ans |= (n & 1) << (31 - i)
- Right shift
n
by 1 to process the next bit:n >>= 1
This process continues for all 32 bits, effectively reversing the entire bit sequence of the input integer.
Intuition
To reverse the bits of a number, we need to swap the positions of bits symmetrically around the center. The bit at position 0 should go to position 31, the bit at position 1 should go to position 30, and so on.
Think of it like reversing a string - you would take characters from one end and place them at the opposite end. Similarly, with bits, we need to take each bit from its current position and place it at its mirror position.
The key insight is that we can process the bits one by one from right to left (least significant to most significant). As we examine each bit:
- We need to extract it from its current position
- We need to place it at its new reversed position
To extract the rightmost bit, we use n & 1
, which gives us the value (0 or 1) of the least significant bit.
To place this bit at its reversed position, we need to shift it left. If we're processing the i
-th bit (counting from 0), its reversed position would be 31 - i
. So we shift the extracted bit left by 31 - i
positions using << (31 - i)
.
After processing each bit, we shift n
right by 1 position (n >>= 1
) to bring the next bit into the least significant position for processing in the next iteration.
By accumulating all these repositioned bits using the OR operation (|=
), we build up the reversed number bit by bit. After 32 iterations, we've processed all bits and have our complete reversed result.
This approach is efficient because it processes each bit exactly once and uses simple bitwise operations that are very fast at the hardware level.
Solution Approach
The solution uses bit manipulation to reverse the bits of a 32-bit integer. Let's walk through the implementation step by step:
Algorithm Overview: We iterate through all 32 bits of the input number, extracting each bit from the right side and placing it at the corresponding position on the left side of our result.
Step-by-step Implementation:
-
Initialize the result variable: Start with
ans = 0
, which will store our reversed bit pattern. -
Loop through 32 bits: Use a for loop with
i
ranging from 0 to 31 to process each bit position. -
Extract and reposition each bit: For each iteration
i
:- Extract the rightmost bit of
n
usingn & 1
. This AND operation with 1 gives us the value of the least significant bit (either 0 or 1). - Calculate the reversed position as
31 - i
. Wheni = 0
, the bit goes to position 31; wheni = 31
, the bit goes to position 0. - Shift the extracted bit to its new position using
(n & 1) << (31 - i)
. - Combine this bit with our result using the OR operation:
ans |= (n & 1) << (31 - i)
.
- Extract the rightmost bit of
-
Prepare for next bit: After processing the current bit, right shift
n
by 1 position (n >>= 1
) to bring the next bit into the least significant position for the next iteration.
Example Walkthrough:
Let's say n = 5
(binary: 00000000000000000000000000000101
)
- Iteration 0: Extract bit 1, place at position 31 β
ans = 10000000000000000000000000000000
- Iteration 1: Extract bit 0, place at position 30 β
ans = 10000000000000000000000000000000
- Iteration 2: Extract bit 1, place at position 29 β
ans = 10100000000000000000000000000000
- Continue for remaining 29 iterations...
After all 32 iterations, we return ans
which contains the reversed bit pattern.
Time Complexity: O(1) - We always iterate exactly 32 times regardless of input. Space Complexity: O(1) - We only use a constant amount of extra space.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example with n = 11
(in decimal).
Initial Setup:
- Input:
n = 11
- Binary:
00000000000000000000000000001011
- Result:
ans = 0
Key Iterations:
Iteration 0 (i=0):
- Current
n
:...001011
- Extract rightmost bit:
n & 1 = 1
- Place at position 31:
1 << 31
- Update result:
ans = 10000000000000000000000000000000
- Shift n right:
n = ...000101
Iteration 1 (i=1):
- Current
n
:...000101
- Extract rightmost bit:
n & 1 = 1
- Place at position 30:
1 << 30
- Update result:
ans = 11000000000000000000000000000000
- Shift n right:
n = ...000010
Iteration 2 (i=2):
- Current
n
:...000010
- Extract rightmost bit:
n & 1 = 0
- Place at position 29:
0 << 29
- Result unchanged:
ans = 11000000000000000000000000000000
- Shift n right:
n = ...000001
Iteration 3 (i=3):
- Current
n
:...000001
- Extract rightmost bit:
n & 1 = 1
- Place at position 28:
1 << 28
- Update result:
ans = 11010000000000000000000000000000
- Shift n right:
n = ...000000
Iterations 4-31:
- Since
n = 0
after iteration 3, all remaining bits are 0 n & 1 = 0
for all remaining iterations- The result remains:
ans = 11010000000000000000000000000000
Final Result:
- Binary:
11010000000000000000000000000000
- Decimal:
3489660928
The original bits 1011
from the rightmost positions have been moved to the leftmost positions as 1101
, effectively reversing the bit pattern across the entire 32-bit integer.
Solution Implementation
1class Solution:
2 def reverseBits(self, n: int) -> int:
3 """
4 Reverse the bits of a 32-bit unsigned integer.
5
6 Args:
7 n: A 32-bit unsigned integer to reverse
8
9 Returns:
10 The integer with bits reversed
11 """
12 result = 0
13
14 # Process all 32 bits
15 for i in range(32):
16 # Extract the least significant bit from n using AND operation
17 # Shift it to its reversed position (31-i) and add to result using OR
18 result |= (n & 1) << (31 - i)
19
20 # Right shift n by 1 to process the next bit in the next iteration
21 n >>= 1
22
23 return result
24
1public class Solution {
2 /**
3 * Reverses the bits of a 32-bit unsigned integer.
4 * For example: 00000010100101000001111010011100 becomes 00111001011110000010100101000000
5 *
6 * @param n - the input integer to reverse (treated as unsigned)
7 * @return the integer with reversed bits
8 */
9 public int reverseBits(int n) {
10 int result = 0;
11
12 // Process all 32 bits
13 for (int bitPosition = 0; bitPosition < 32 && n != 0; bitPosition++) {
14 // Extract the least significant bit (rightmost) from n
15 int currentBit = n & 1;
16
17 // Place the extracted bit at the mirrored position from the left
18 // (31 - bitPosition) calculates the reverse position
19 result |= currentBit << (31 - bitPosition);
20
21 // Right shift n by 1 position (unsigned shift to handle negative numbers correctly)
22 n >>>= 1;
23 }
24
25 return result;
26 }
27}
28
1class Solution {
2public:
3 uint32_t reverseBits(uint32_t n) {
4 uint32_t result = 0;
5
6 // Process each bit position (up to 32 bits)
7 // Early termination when n becomes 0 (optimization)
8 for (int i = 0; i < 32 && n != 0; ++i) {
9 // Extract the least significant bit (LSB) of n
10 // Place it at position (31 - i) in the result
11 result |= (n & 1) << (31 - i);
12
13 // Shift n right by 1 to process the next bit
14 n >>= 1;
15 }
16
17 return result;
18 }
19};
20
1/**
2 * Reverses the bits of a 32-bit unsigned integer
3 * @param n - A positive integer to reverse bits for
4 * @returns The integer with bits reversed
5 */
6function reverseBits(n: number): number {
7 let result: number = 0;
8
9 // Process each of the 32 bits
10 for (let i = 0; i < 32 && n > 0; i++) {
11 // Extract the rightmost bit of n using bitwise AND with 1
12 // Then shift it to its reversed position (31 - i) and OR it with result
13 result |= (n & 1) << (31 - i);
14
15 // Right shift n by 1 to process the next bit
16 n >>= 1;
17 }
18
19 // Use unsigned right shift to ensure the result is treated as unsigned 32-bit integer
20 return result >>> 0;
21}
22
Time and Space Complexity
The time complexity is O(1)
, not O(log n)
as stated in the reference answer. This is because the loop always runs exactly 32 iterations regardless of the input value n
. Even though we're processing a 32-bit integer, the number of operations is constant and doesn't scale with the magnitude of n
.
The space complexity is O(1)
, which matches the reference answer. The algorithm only uses a fixed amount of extra space for the variable ans
and the loop counter i
, regardless of the input size.
The reference answer appears to be incorrect regarding time complexity. For this specific problem of reversing bits in a 32-bit integer, the time complexity should be O(1)
since we always perform exactly 32 iterations. If this were a more general bit reversal problem where the number of bits varied with n
, then O(log n)
would be appropriate since the number of bits in n
is proportional to log n
.
Common Pitfalls
1. Early Termination When n Becomes 0
A common mistake is to optimize by breaking the loop early when n
becomes 0, thinking all remaining bits are 0:
# INCORRECT approach
def reverseBits(self, n: int) -> int:
result = 0
for i in range(32):
if n == 0: # Wrong! This causes incorrect results
break
result |= (n & 1) << (31 - i)
n >>= 1
return result
Why this fails: Even if n
becomes 0 during iteration, we still need to continue placing zeros in the remaining positions. Breaking early leaves those positions unprocessed, resulting in incorrect bit placement.
Example: For n = 1
(binary: 00000000000000000000000000000001
), the correct reversal is 10000000000000000000000000000000
(2147483648). But breaking early after the first iteration would incorrectly return 2147483648 without properly handling the remaining bit positions.
2. Using Wrong Shift Direction or Amount
Another pitfall is confusing the shift operations:
# INCORRECT approaches result |= (n & 1) << i # Wrong: shifts to wrong position result |= (n & 1) >> (31 - i) # Wrong: uses right shift instead of left result |= (n >> 1) << (31 - i) # Wrong: extracts wrong bit
Solution: Always remember:
- Use
n & 1
to extract the rightmost bit - Use
<< (31 - i)
to place it at the reversed position - Use
n >>= 1
to move to the next bit
3. Incorrect Bit Position Calculation
Some might incorrectly calculate the reversed position:
# INCORRECT result |= (n & 1) << (32 - i) # Wrong: shifts by 32 to 1 instead of 31 to 0 result |= (n & 1) << (30 - i) # Wrong: incorrect range
Solution: The correct formula is 31 - i
because:
- Bit positions range from 0 to 31 (total 32 positions)
- When
i = 0
, we want position 31 - When
i = 31
, we want position 0
4. Not Processing All 32 Bits
Processing fewer than 32 bits leads to incomplete reversal:
# INCORRECT
for i in range(16): # Wrong: only processes half the bits
result |= (n & 1) << (31 - i)
n >>= 1
Solution: Always iterate exactly 32 times to ensure all bits are properly reversed, regardless of the input value.
What's the output of running the following function using input [30, 20, 10, 100, 33, 12]
?
1def fun(arr: List[int]) -> List[int]:
2 import heapq
3 heapq.heapify(arr)
4 res = []
5 for i in range(3):
6 res.append(heapq.heappop(arr))
7 return res
8
1public static int[] fun(int[] arr) {
2 int[] res = new int[3];
3 PriorityQueue<Integer> heap = new PriorityQueue<>();
4 for (int i = 0; i < arr.length; i++) {
5 heap.add(arr[i]);
6 }
7 for (int i = 0; i < 3; i++) {
8 res[i] = heap.poll();
9 }
10 return res;
11}
12
1class HeapItem {
2 constructor(item, priority = item) {
3 this.item = item;
4 this.priority = priority;
5 }
6}
7
8class MinHeap {
9 constructor() {
10 this.heap = [];
11 }
12
13 push(node) {
14 // insert the new node at the end of the heap array
15 this.heap.push(node);
16 // find the correct position for the new node
17 this.bubble_up();
18 }
19
20 bubble_up() {
21 let index = this.heap.length - 1;
22
23 while (index > 0) {
24 const element = this.heap[index];
25 const parentIndex = Math.floor((index - 1) / 2);
26 const parent = this.heap[parentIndex];
27
28 if (parent.priority <= element.priority) break;
29 // if the parent is bigger than the child then swap the parent and child
30 this.heap[index] = parent;
31 this.heap[parentIndex] = element;
32 index = parentIndex;
33 }
34 }
35
36 pop() {
37 const min = this.heap[0];
38 this.heap[0] = this.heap[this.size() - 1];
39 this.heap.pop();
40 this.bubble_down();
41 return min;
42 }
43
44 bubble_down() {
45 let index = 0;
46 let min = index;
47 const n = this.heap.length;
48
49 while (index < n) {
50 const left = 2 * index + 1;
51 const right = left + 1;
52
53 if (left < n && this.heap[left].priority < this.heap[min].priority) {
54 min = left;
55 }
56 if (right < n && this.heap[right].priority < this.heap[min].priority) {
57 min = right;
58 }
59 if (min === index) break;
60 [this.heap[min], this.heap[index]] = [this.heap[index], this.heap[min]];
61 index = min;
62 }
63 }
64
65 peek() {
66 return this.heap[0];
67 }
68
69 size() {
70 return this.heap.length;
71 }
72}
73
74function fun(arr) {
75 const heap = new MinHeap();
76 for (const x of arr) {
77 heap.push(new HeapItem(x));
78 }
79 const res = [];
80 for (let i = 0; i < 3; i++) {
81 res.push(heap.pop().item);
82 }
83 return res;
84}
85
Recommended Readings
https assets algo monster cover_photos dnd svg Divide and Conquer The main idea of divide and conquer is to split the main problem into two smaller components assuming that each one of the components had already been solved recursively and then try to solve the bigger problem using the solutions
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donβt Miss This!