Hamming Distance
EasyPrompt
The Hamming distance between two integers is the number of positions at which the corresponding bits are different.
Given two integers x and y, return the Hamming distance between them.
Example 1:
Input: x = 1, y = 4
Output: 2
Explanation:
1 (0 0 0 1)
4 (0 1 0 0)
↑ ↑
The above arrows point to positions where the corresponding bits are different.Example 2:
Input: x = 3, y = 1
Output: 1
Constraints:
0 <= x, y <= 231 - 1
Note: This question is the same as 2220: Minimum Bit Flips to Convert Number.
Approaches
5 approaches with complexity analysis and trade-offs.
This approach converts both integers into their binary string representations. It then compares these strings character by character to count the differences. To handle numbers of different bit lengths, the shorter string is padded with leading zeros to match the length of the longer one.
Algorithm
- Convert
xto a binary string usingInteger.toBinaryString(x). - Convert
yto a binary string usingInteger.toBinaryString(y). - Determine the maximum length of the two strings.
- Pad the shorter string with leading '0's so both strings have the same length.
- Iterate from
0tolength - 1. - In each iteration, compare the characters at the current index. If they are different, increment a
distancecounter. - Return the final
distance.
Walkthrough
This method is straightforward but less performant. It relies on standard library functions to convert numbers to strings and then performs a character-by-character comparison.
- Convert both integers
xandyto their binary string representations. - Since the binary strings can have different lengths (e.g.,
Integer.toBinaryString(1)is"1"andInteger.toBinaryString(4)is"100"), we need to make them equal in length by padding the shorter string with leading zeros. - Once they have the same length, we can iterate through them and count the positions where the characters (bits) do not match.
class Solution { public int hammingDistance(int x, int y) { String xStr = Integer.toBinaryString(x); String yStr = Integer.toBinaryString(y); int lenX = xStr.length(); int lenY = yStr.length(); int maxLen = Math.max(lenX, lenY); // Pad with leading zeros while (xStr.length() < maxLen) { xStr = "0" + xStr; } while (yStr.length() < maxLen) { yStr = "0" + yStr; } int distance = 0; for (int i = 0; i < maxLen; i++) { if (xStr.charAt(i) != yStr.charAt(i)) { distance++; } } return distance; }}Complexity
Time
O(k), where k is the number of bits in the larger number. String conversions, padding, and iteration all take time proportional to the number of bits. For 32-bit integers, this is effectively O(1) but with a high constant factor.
Space
O(k), where k is the number of bits in the larger number (at most 32). This space is used to store the binary string representations.
Trade-offs
Pros
Conceptually simple and easy to understand for those less familiar with bitwise operations.
Cons
Inefficient due to the overhead of string creation, manipulation, and memory allocation.
Slower than direct bitwise manipulation.
Requires extra space to store the string representations.
This approach iterates through each bit of the two numbers, from the least significant bit to the most significant bit. In each iteration, it uses bitwise operations to extract and compare the corresponding bits of x and y and increments a counter if they differ.
Algorithm
- Initialize
distance = 0. - Loop 32 times, for each bit position
ifrom 0 to 31. - Extract the
i-th bit ofxandyusing right shift and AND operations:(x >> i) & 1and(y >> i) & 1. - If the bits are different, increment
distance. - Return
distanceafter the loop.
Walkthrough
Instead of converting to strings, we can work directly with the integer representations. Since integers are stored as a fixed number of bits (32 in this case), we can loop 32 times and check each bit position individually.
- We use a loop that runs from
i = 0to31. - In each iteration, we isolate the
i-th bit of bothxandy. This is done by right-shifting the number byipositions, which moves thei-th bit to the least significant position, and then performing a bitwise AND with 1. - We compare these two extracted bits. If they are not equal, we increment our distance counter.
- After checking all 32 bits, the counter holds the Hamming distance.
class Solution { public int hammingDistance(int x, int y) { int distance = 0; for (int i = 0; i < 32; i++) { // Extract the i-th bit of x and y int bitX = (x >> i) & 1; int bitY = (y >> i) & 1; if (bitX != bitY) { distance++; } } return distance; }}Complexity
Time
O(k), where k is the number of bits in an integer (fixed at 32). The loop runs a constant number of times. Therefore, the complexity is O(1).
Space
O(1), as we only use a few variables for the counter and loop index.
Trade-offs
Pros
More efficient than the string-based approach as it avoids string overhead.
Constant time and space complexity.
Cons
It always performs a fixed number of iterations (32), regardless of the actual values of x and y, which might be inefficient for small numbers.
A more elegant bit manipulation approach first computes the bitwise XOR of x and y. The XOR operation x ^ y results in a number where a bit is set to 1 if and only if the corresponding bits in x and y were different. The problem then reduces to counting the number of set bits (1s) in the result of the XOR operation. This is also known as calculating the population count or Hamming weight.
Algorithm
- Compute
xor_result = x ^ y. - Initialize
distance = 0. - While
xor_resultis not zero:- Add
(xor_result & 1)todistance. - Right shift
xor_resultby 1 (xor_result = xor_result >> 1).
- Add
- Return
distance.
Walkthrough
The key insight is that the Hamming distance is the number of set bits in the XOR of the two numbers.
- First, calculate
xor_result = x ^ y. This single operation effectively marks all differing bit positions with a '1'. - Now, we need to count the set bits in
xor_result. - We can do this by repeatedly checking the least significant bit (LSB) and then right-shifting the number until it becomes zero.
- In a loop that continues as long as
xor_result > 0:- Check if the LSB is 1 using
(xor_result & 1) == 1. If it is, incrementdistance. - Right-shift
xor_resultby one position (xor_result = xor_result >> 1) to process the next bit.
- Check if the LSB is 1 using
class Solution { public int hammingDistance(int x, int y) { int xor_result = x ^ y; int distance = 0; while (xor_result != 0) { distance += (xor_result & 1); // Use unsigned right shift >>> if dealing with negative numbers, // but constraints are non-negative. >> is fine here. xor_result = xor_result >> 1; } return distance; }}Complexity
Time
O(k), where k is the number of bits in the integer (32). The loop runs up to k times, depending on the position of the most significant set bit in `x ^ y`. For a fixed integer size, this is O(1).
Space
O(1), as only a few variables are used.
Trade-offs
Pros
More concise and often slightly faster in practice than direct bit-by-bit comparison of two numbers.
The number of iterations depends on the position of the highest set bit, not always 32.
Cons
The loop still iterates over all bits up to the most significant '1', including the '0's in between, which is less efficient than algorithms that only visit set bits.
This is a clever optimization for counting set bits, often known as Brian Kernighan's algorithm. Instead of shifting through all bits, this algorithm repeatedly eliminates the rightmost set bit. The number of times this operation can be performed is exactly equal to the number of set bits. The key operation is n & (n - 1), which unsets the rightmost '1' bit of n.
Algorithm
- Compute
xor_result = x ^ y. - Initialize
distance = 0. - While
xor_resultis not zero:- Increment
distance. - Update
xor_resulttoxor_result & (xor_result - 1).
- Increment
- Return
distance.
Walkthrough
This approach improves upon the previous one by reducing the number of loop iterations. The number of iterations will be exactly equal to the number of set bits, which is the Hamming distance we are looking for.
- As before, calculate
xor_result = x ^ y. - Initialize a
distancecounter to 0. - In a loop that continues as long as
xor_result > 0:- In each iteration, we know there is at least one set bit. We increment the
distancecounter. - Then, we turn off the rightmost set bit using the operation:
xor_result = xor_result & (xor_result - 1). For example, ifxor_resultis12(binary1100),xor_result - 1is11(binary1011).1100 & 1011is1000(binary8). The rightmost '1' has been turned off.
- In each iteration, we know there is at least one set bit. We increment the
- The loop terminates when
xor_resultbecomes 0, meaning all set bits have been removed.
class Solution { public int hammingDistance(int x, int y) { int xor_result = x ^ y; int distance = 0; while (xor_result != 0) { // This operation removes the rightmost set bit xor_result = xor_result & (xor_result - 1); distance++; } return distance; }}Complexity
Time
O(m), where m is the number of set bits in `x ^ y` (i.e., the Hamming distance). This is more efficient because the number of loop iterations is not tied to the total number of bits, but to the number of differing bits. In the worst case, m can be k (32), but on average, it's much better.
Space
O(1).
Trade-offs
Pros
Highly efficient. The number of operations is proportional to the Hamming distance itself, not the total number of bits.
Outperforms other manual bit-counting methods on average.
Cons
The logic
n & (n - 1)might be less intuitive for beginners compared to simpler bit-shifting.
Most modern programming languages and processors provide a highly optimized built-in function to count the number of set bits in an integer (population count). This is almost always the fastest and most concise way to solve the problem.
Algorithm
- Compute
xor_result = x ^ y. - Return the result of
Integer.bitCount(xor_result).
Walkthrough
This approach leverages the standard library for maximum efficiency and conciseness. The logic is extremely simple.
- First, calculate the bitwise XOR of the two numbers:
xor_result = x ^ y. - Then, use the language's built-in function to count the set bits in
xor_result. In Java, this function isInteger.bitCount().
This function is often mapped to a single, fast machine instruction (like POPCNT on x86 processors), making it extremely efficient.
class Solution { public int hammingDistance(int x, int y) { return Integer.bitCount(x ^ y); }}Complexity
Time
O(1). The operation is typically a single CPU instruction, making it constant time and extremely fast.
Space
O(1).
Trade-offs
Pros
The most efficient and concise solution.
It's readable and leverages hardware optimizations.
Cons
Relies on a built-in library function, which might not be allowed in some interview settings that want you to implement the logic from scratch.
Solutions
Solution
class Solution {public int hammingDistance(int x, int y) { return Integer.bitCount(x ^ y); }}/** * @param {number} x * @param {number} y * @return {number} */ var hammingDistance = function (x, y) { x ^= y; let ans = 0; while (x) { x -= x & -x; ++ans; } return ans; };class Solution {public: int hammingDistance(int x, int y) { return __builtin_popcount(x ^ y); }};class Solution: def hammingDistance( self, x: int, y: int) -> int: return (x ^ y). bit_count()Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.