A clear explanation of finding the bitwise complement of a positive integer using a binary mask.
Problem Restatement
We are given a positive integer num.
We need to flip every bit in its binary representation:
| Bit | After flip |
|---|---|
0 | 1 |
1 | 0 |
Then we return the decimal value of the flipped binary number.
For example, 5 in binary is:
101After flipping every bit:
010010 in binary is 2, so the answer is 2.
The problem uses the normal binary representation without leading zeroes. This matters because we only flip the bits that are actually part of num.
Input and Output
| Item | Meaning |
|---|---|
| Input | A positive integer num |
| Output | The integer complement of num |
| Constraint | 1 <= num < 2^31 |
Function shape:
def findComplement(num: int) -> int:
...Examples
Example 1:
num = 5Binary form:
101Flip every bit:
010Return:
2Example 2:
num = 1Binary form:
1Flip every bit:
0Return:
0First Thought: Convert to String
A simple way is to convert the number to binary text.
For example:
bin(5) == "0b101"Then we can remove the "0b" prefix, flip each character, and convert the result back to an integer.
class Solution:
def findComplement(self, num: int) -> int:
bits = bin(num)[2:]
flipped = []
for ch in bits:
if ch == "0":
flipped.append("1")
else:
flipped.append("0")
return int("".join(flipped), 2)This works, and it is easy to understand.
Problem With the String Method
The string method depends on converting between integer and text.
That is fine for this problem, but the problem is really about bits. A direct bit manipulation solution is shorter and closer to the idea.
We want to flip only the meaningful bits of num.
For num = 5, the meaningful bits are:
101We do not want to think of it as a 32-bit integer like this:
00000000000000000000000000000101If we directly use ~num, Python gives a negative result because Python integers use signed arithmetic behavior for bitwise complement.
So we need a mask.
Key Insight
To flip exactly the bits of num, build a mask with the same number of bits, all set to 1.
For num = 5:
num = 101
mask = 111Now XOR flips every bit where the mask has 1.
101
111
---
010So:
5 ^ 7 == 2The mask for a number with k bits is:
(1 << k) - 1For num = 5, k = 3.
1 << 3 == 8 # binary 1000
8 - 1 == 7 # binary 0111So the mask is 7, or 111 in binary.
Algorithm
First, find how many bits are needed to represent num.
Python gives this directly:
k = num.bit_length()Then build the mask:
mask = (1 << k) - 1Then flip the bits by XOR:
answer = num ^ maskReturn answer.
Correctness
Let k be the number of bits in the binary representation of num.
The mask:
(1 << k) - 1has exactly k bits, and every one of those bits is 1.
For every bit position used by num, XOR with 1 flips the bit:
| Original bit | Mask bit | XOR result |
|---|---|---|
0 | 1 | 1 |
1 | 1 | 0 |
Therefore, num ^ mask flips every bit in the binary representation of num.
The mask has no extra 1 bits beyond the length of num, so no leading positions are changed.
Thus the algorithm returns exactly the complement required by the problem.
Complexity
| Metric | Value | Why |
|---|---|---|
| Time | O(1) | num < 2^31, so there are at most 31 bits |
| Space | O(1) | Only a few integer variables are used |
If we write the complexity in terms of the number of bits k, the time is O(k) for computing bit length and bit operations. Under the given constraint, k <= 31, so it is constant.
Implementation
class Solution:
def findComplement(self, num: int) -> int:
k = num.bit_length()
mask = (1 << k) - 1
return num ^ maskCode Explanation
This line gets the number of meaningful bits:
k = num.bit_length()For example:
num | Binary | bit_length() |
|---|---|---|
1 | 1 | 1 |
5 | 101 | 3 |
10 | 1010 | 4 |
This line creates a mask of k ones:
mask = (1 << k) - 1For k = 4:
1 << 4 = 10000
10000 - 1 = 01111Then this line flips all meaningful bits:
return num ^ maskFor num = 10:
num = 1010
mask = 1111
xor = 0101So the answer is 5.
Testing
def run_tests():
s = Solution()
assert s.findComplement(5) == 2
assert s.findComplement(1) == 0
assert s.findComplement(10) == 5
assert s.findComplement(7) == 0
assert s.findComplement(8) == 7
print("all tests passed")
run_tests()Test meaning:
| Test | Why |
|---|---|
5 -> 2 | Main example: 101 -> 010 |
1 -> 0 | Smallest valid input |
10 -> 5 | Alternating bits: 1010 -> 0101 |
7 -> 0 | All bits are 1: 111 -> 000 |
8 -> 7 | Power of two: 1000 -> 0111 |