LeetCode 461 - Hamming Distance
The problem asks us to compute the Hamming distance between two integers. The Hamming distance is defined as the number of bit positions where the two numbers differ in their binary representation. For example, consider x = 1 and y = 4.
Difficulty: 🟢 Easy
Topics: Bit Manipulation
Solution
Problem Understanding
The problem asks us to compute the Hamming distance between two integers. The Hamming distance is defined as the number of bit positions where the two numbers differ in their binary representation.
For example, consider x = 1 and y = 4.
Their binary representations are:
1 = 00014 = 0100
If we compare the bits position by position:
| Position | x | y | Different? |
|---|---|---|---|
| 1 | 1 | 0 | Yes |
| 2 | 0 | 0 | No |
| 3 | 0 | 1 | Yes |
| 4 | 0 | 0 | No |
There are exactly two positions where the bits differ, so the Hamming distance is 2.
The input consists of two non-negative integers, x and y. The output is a single integer representing how many bit positions are different.
The constraints tell us that:
0 <= x, y <= 2^31 - 1
This means both integers fit within a standard 32-bit signed integer range. Since the numbers are relatively small in terms of bit length, any solution that processes all bits individually is already efficient enough.
An important observation is that we are not comparing decimal digits or string representations. The comparison must happen at the binary bit level.
Several edge cases are important to consider:
- When
x == y, the answer should be0because all bits match. - When one number is
0, the answer becomes the number of set bits in the other number. - Large values near
2^31 - 1must still work correctly. - Leading zeros do not matter because binary comparison naturally aligns bits by position.
Approaches
Brute Force Approach
A straightforward solution is to compare every bit position one by one.
We can repeatedly examine the least significant bit of both numbers using bitwise AND:
x & 1
y & 1
If these bits differ, we increment the answer.
After checking the current bit, we shift both numbers right by one position and continue until all bits have been processed.
Since integers are at most 31 bits long under the constraints, this approach works efficiently enough.
The brute-force method is correct because every bit position is explicitly checked exactly once. If two corresponding bits differ, that contributes exactly one to the Hamming distance.
Optimal Approach
The key insight comes from the XOR operation.
Recall the behavior of XOR:
| Bit A | Bit B | A XOR B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
Notice that XOR produces 1 exactly when the bits are different.
Therefore:
x ^ y
creates a number where every set bit represents a differing bit position.
After computing the XOR, the problem reduces to counting how many set bits are present.
We can count set bits efficiently using Brian Kernighan’s algorithm:
n = n & (n - 1)
This operation removes the lowest set bit from the number. Repeating this process counts all set bits efficiently.
Approach Comparison
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(32) | O(1) | Checks every bit position individually |
| Optimal | O(k) | O(1) | Uses XOR and removes one set bit per iteration |
Here, k represents the number of set bits in x ^ y.
Algorithm Walkthrough
Optimal Algorithm
- Compute the XOR of
xandy.
difference = x ^ y
XOR produces 1 wherever the bits differ and 0 wherever they match.
2. Initialize a counter variable.
distance = 0
This variable will track how many differing bit positions exist. 3. While the XOR result is not zero, repeatedly remove the lowest set bit.
difference = difference & (difference - 1)
This operation removes exactly one set bit from the number. 4. Increment the counter after each removal.
Since each iteration removes one set bit, the number of iterations equals the number of differing bits. 5. Continue until the XOR result becomes zero.
At that point, all differing bits have been counted. 6. Return the counter as the final Hamming distance.
Why it works
The correctness comes from two properties:
x ^ yproduces1exactly at positions where the bits differ.n & (n - 1)removes exactly one set bit fromn.
Therefore, repeatedly applying the second operation counts exactly how many differing bit positions exist between x and y.
Python Solution
class Solution:
def hammingDistance(self, x: int, y: int) -> int:
difference = x ^ y
distance = 0
while difference:
difference &= difference - 1
distance += 1
return distance
The implementation begins by computing the XOR of x and y. This isolates all differing bit positions into a single integer called difference.
The variable distance stores the number of differing bits found so far.
The while loop continues as long as there is at least one set bit remaining in difference.
Inside the loop, the statement:
difference &= difference - 1
removes the lowest set bit. Since each iteration removes exactly one set bit, incrementing distance counts one differing position.
Once all set bits are removed, difference becomes zero and the loop stops. The final value of distance is returned.
Go Solution
func hammingDistance(x int, y int) int {
difference := x ^ y
distance := 0
for difference != 0 {
difference &= difference - 1
distance++
}
return distance
}
The Go implementation follows the exact same logic as the Python version.
The primary difference is syntax. Go uses := for variable declaration and a for loop instead of Python’s while loop.
No special overflow handling is required because the constraints guarantee that the values fit within standard integer ranges.
Worked Examples
Example 1
Input:
x = 1
y = 4
Binary representations:
1 = 0001
4 = 0100
Compute XOR:
0001
0100
----
0101
So:
difference = 5
Now count set bits.
| Iteration | difference (binary) | Operation | New difference | distance |
|---|---|---|---|---|
| Start | 0101 | Initial value | 0101 | 0 |
| 1 | 0101 | 0101 & 0100 | 0100 | 1 |
| 2 | 0100 | 0100 & 0011 | 0000 | 2 |
The loop ends because difference becomes 0.
Final answer:
2
Example 2
Input:
x = 3
y = 1
Binary representations:
3 = 0011
1 = 0001
Compute XOR:
0011
0001
----
0010
So:
difference = 2
Now count set bits.
| Iteration | difference (binary) | Operation | New difference | distance |
|---|---|---|---|---|
| Start | 0010 | Initial value | 0010 | 0 |
| 1 | 0010 | 0010 & 0001 | 0000 | 1 |
Final answer:
1
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(k) | Each iteration removes one set bit |
| Space | O(1) | Only a few integer variables are used |
The runtime depends on the number of set bits in x ^ y, not the total number of bits in the integers. In the worst case, there can be at most 31 set bits due to the constraints, so the algorithm is extremely efficient.
The space complexity is constant because no additional data structures are allocated.
Test Cases
solution = Solution()
assert solution.hammingDistance(1, 4) == 2 # Example 1
assert solution.hammingDistance(3, 1) == 1 # Example 2
assert solution.hammingDistance(0, 0) == 0 # Both numbers identical
assert solution.hammingDistance(0, 7) == 3 # Count set bits in one number
assert solution.hammingDistance(7, 0) == 3 # Reverse order of previous test
assert solution.hammingDistance(15, 15) == 0 # All bits match
assert solution.hammingDistance(8, 0) == 1 # Single set bit
assert solution.hammingDistance(255, 0) == 8 # Multiple consecutive set bits
assert solution.hammingDistance(1023, 511) == 1 # Only highest bit differs
assert solution.hammingDistance(2147483647, 0) == 31 # Maximum constraint value
assert solution.hammingDistance(2147483647, 2147483647) == 0 # Maximum equal values
| Test | Why |
|---|---|
(1, 4) |
Validates the first provided example |
(3, 1) |
Validates the second provided example |
(0, 0) |
Tests identical zero values |
(0, 7) |
Tests counting set bits directly |
(7, 0) |
Ensures symmetry of the operation |
(15, 15) |
Tests identical non-zero values |
(8, 0) |
Tests a single differing bit |
(255, 0) |
Tests many consecutive set bits |
(1023, 511) |
Tests a high-bit difference |
(2147483647, 0) |
Tests maximum constraint size |
(2147483647, 2147483647) |
Tests maximum equal values |
Edge Cases
One important edge case occurs when both numbers are identical. In that situation, every bit matches, so the XOR result becomes zero immediately. The loop never executes, and the algorithm correctly returns 0.
Another important case occurs when one number is zero. In this scenario, the Hamming distance equals the number of set bits in the other number. The XOR operation naturally handles this because 0 ^ n = n. The implementation correctly counts all set bits using Brian Kernighan’s algorithm.
A third edge case involves very large numbers near the upper constraint limit. For example, 2147483647 contains 31 set bits. Some implementations might incorrectly assume a fixed smaller bit width or mishandle integer operations. This solution works correctly because it relies entirely on standard bitwise operations and processes all set bits regardless of their position.
Another subtle edge case is when only one bit differs between the numbers. In that case, the XOR result contains exactly one set bit, and the loop executes exactly once. The implementation naturally handles this efficiently.