LeetCode 190 - Reverse Bits
The problem asks us to reverse the binary representation of a 32-bit integer. Instead of reversing the decimal digits of a number, we reverse the order of its individual bits.
Difficulty: 🟢 Easy
Topics: Divide and Conquer, Bit Manipulation
Solution
Problem Understanding
The problem asks us to reverse the binary representation of a 32-bit integer. Instead of reversing the decimal digits of a number, we reverse the order of its individual bits.
For example, suppose the binary representation of a number is:
00000010100101000001111010011100
After reversing all 32 bits, it becomes:
00111001011110000010100101000000
The resulting reversed binary value is then converted back into an integer and returned.
A key detail is that we must always treat the input as a 32-bit value, even if leading zeros exist. Normally, binary numbers ignore leading zeros, but in this problem they matter because reversing bits changes their position. For example, reversing 1 is not 1, it becomes:
00000000000000000000000000000001
→ reversed →
10000000000000000000000000000000
This produces a completely different integer.
The input n represents a non-negative integer constrained by:
0 <= n <= 2³¹ - 2nis guaranteed to be even
Although the prompt mentions a signed integer, the actual operation is purely bit manipulation over a fixed 32-bit representation. Since the input range is bounded and fixed to 32 bits, we know that any efficient solution should ideally process exactly 32 positions.
Several edge cases are important to think about upfront. An input of 0 should remain 0 because every bit is zero. Numbers with only a single set bit, such as powers of two, can move that bit to the opposite side of the 32-bit representation after reversal. Inputs with many leading zeros are also important because those zeros become trailing zeros after reversal, and vice versa. Finally, since the problem always works with exactly 32 bits, forgetting to process all 32 positions would produce incorrect answers.
Approaches
Brute Force Approach
A straightforward way to solve this problem is to first convert the number into a 32-bit binary string, reverse the string, and then convert the reversed binary representation back into an integer.
For example:
- Convert
43261596to a 32-character binary string. - Reverse the string.
- Parse the reversed binary string as an integer.
This approach works because reversing the string exactly mirrors the required bit reversal operation. However, string manipulation introduces unnecessary overhead. We are solving a bit manipulation problem, so repeatedly converting between integers and strings is less efficient and less elegant than directly operating on bits.
Since the binary representation always has a fixed length of 32, the brute-force approach still runs in constant time in practice. However, conceptually it performs additional conversion work and uses extra memory.
Optimal Approach
The key insight is that we can construct the reversed number directly using bit manipulation.
We process the bits of n one at a time from right to left. At each step:
- Extract the least significant bit from
n - Shift the result left to make room for the next bit
- Add the extracted bit into the result
- Shift
nright to continue processing
Why does this work?
When reversing bits, the least significant bit of the original number becomes the most significant bit of the result. By repeatedly taking bits from right to left and appending them to the left side of the answer, we naturally build the reversed binary representation.
Since the input is always exactly 32 bits, we repeat this process exactly 32 times.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(32) | O(32) | Convert to binary string, reverse it, convert back |
| Optimal | O(32) | O(1) | Reverse bits directly using bit operations |
Even though both are technically constant time because 32 is fixed, the optimal method is preferred because it uses no extra storage and demonstrates proper bit manipulation.
Algorithm Walkthrough
- Initialize a variable called
resultto0. This variable will store the reversed bit sequence as we build it incrementally. - Iterate exactly 32 times. We must always process all 32 bits, including leading zeros, because they affect the final reversed result.
- Extract the least significant bit of
nusingn & 1. The bitwise AND operation with1isolates the rightmost bit. - Shift
resultone position to the left usingresult << 1. This creates space for the new bit we are about to append. - Add the extracted bit into
resultusing bitwise OR (|). This inserts the current bit into the correct position. - Shift
none position to the right usingn >> 1. This removes the processed bit and moves the next bit into position. - After completing all 32 iterations, return
result.
The reason this works is that every extracted bit is appended in reverse order. The first bit removed from n becomes the highest-positioned bit in the final answer.
Python Solution
class Solution:
def reverseBits(self, n: int) -> int:
result = 0
for _ in range(32):
bit = n & 1
result = (result << 1) | bit
n >>= 1
return result
The implementation begins by initializing result to 0, which acts as the accumulator for the reversed number.
The loop runs exactly 32 times because the problem explicitly works with a fixed 32-bit representation. During each iteration, we isolate the rightmost bit of n using n & 1.
Next, result is shifted left by one position to create room for the new bit. We then insert the extracted bit using a bitwise OR operation.
Finally, n is shifted right to prepare for the next iteration. This continues until every bit has been processed.
By the end of the loop, the reversed 32-bit integer has been fully reconstructed and returned.
Go Solution
func reverseBits(n int) int {
result := 0
for i := 0; i < 32; i++ {
bit := n & 1
result = (result << 1) | bit
n >>= 1
}
return result
}
The Go implementation follows exactly the same logic as the Python version. Since Go integers support bitwise operations directly, the implementation remains concise.
One important consideration is integer types. LeetCode's original problem typically uses uint32, but the provided function signature uses int, so we follow it exactly. Since the constraints guarantee a valid 32-bit non-negative number, shifting operations behave safely here.
Unlike Python, Go has fixed-width integer behavior depending on architecture, but because we only process 32 bits and remain within valid ranges, overflow is not an issue.
Worked Examples
Example 1
Input: n = 43261596
Binary form:
00000010100101000001111010011100
We process one bit at a time.
| Iteration | Current Bit (n & 1) |
Result After Shift and Add | n After Right Shift |
|---|---|---|---|
| 1 | 0 | 0 | 21630798 |
| 2 | 0 | 0 | 10815399 |
| 3 | 1 | 1 | 5407699 |
| 4 | 1 | 3 | 2703849 |
| 5 | 1 | 7 | 1351924 |
| ... | ... | ... | ... |
| 32 | Final bit processed | 964176192 | 0 |
Final result:
00111001011110000010100101000000
Output:
964176192
Example 2
Input: n = 2147483644
Binary form:
01111111111111111111111111111100
We again process all 32 bits.
| Iteration | Current Bit (n & 1) |
Result After Shift and Add | n After Right Shift |
|---|---|---|---|
| 1 | 0 | 0 | 1073741822 |
| 2 | 0 | 0 | 536870911 |
| 3 | 1 | 1 | 268435455 |
| 4 | 1 | 3 | 134217727 |
| 5 | 1 | 7 | 67108863 |
| ... | ... | ... | ... |
| 32 | Final bit processed | 1073741822 | 0 |
Final reversed binary:
00111111111111111111111111111110
Output:
1073741822
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(32) | We always process exactly 32 bits |
| Space | O(1) | Only a few integer variables are used |
Although the algorithm is technically O(32), the number of operations is fixed and independent of input size, making it effectively constant time. The space complexity is constant because no additional data structures proportional to input size are allocated.
Edge Cases
Input Is Zero
If n = 0, all 32 bits are zero. Reversing them still results in zero. A careless implementation might terminate early when the number becomes zero, but our implementation explicitly runs 32 iterations, ensuring correctness.
Number With a Single Set Bit
Consider n = 1.
Binary representation:
00000000000000000000000000000001
After reversal:
10000000000000000000000000000000
This demonstrates why processing all 32 bits is essential. If we only processed until n == 0, we would incorrectly return 1.
Numbers With Leading Zeros
A number such as 8:
00000000000000000000000000001000
becomes:
00010000000000000000000000000000
Leading zeros are significant in this problem because they influence the bit positions after reversal. Our fixed 32-iteration loop guarantees they are handled correctly.
Maximum Constraint Value
For values near the upper limit, such as 2³¹ - 2, many bits are set. Since the algorithm only performs fixed-size bit operations exactly 32 times, performance remains constant and efficient regardless of how many bits are 1.
Follow Up: Optimizing for Many Calls
If this function is called many times, we can optimize by using memoization on bytes. Since a byte has only 256 possible values, we can precompute the reversed version of every 8-bit number.
Then:
- Split the 32-bit integer into four bytes.
- Reverse each byte using a lookup table.
- Reassemble them in reversed order.
This reduces repeated computation and makes frequent calls significantly faster.