Data Structures · Bitwise Contribution · A Field Guide

Total Hamming
distance

Sum the differing bits over every pair of numbers. The trick isn't faster pair comparison — it's refusing to look at pairs at all, and counting one bit column at a time.

ones × zeros per bit, summed
01 · Strip it down

Sum the differing-bit count over all pairs

Hamming distance between two numbers = how many bit positions differ, which is exactly the set-bit count of a XOR b. The task is the sum of that over every unordered pair. For [4,14,2] the three pairwise distances are 2, 1, 3 → total 6. The obvious approach compares all n(n−1)/2 pairs — O(n²), too slow for large arrays.


02 · Flip the loops

Count bit by bit, not pair by pair

Hamming distance is additive across bit positions and positions don't interact, so the double sum can be reordered: instead of "for each pair, sum over bits," compute "for each bit, sum over pairs." At one fixed bit, every number shows a 0 or a 1. A pair differs there exactly when one side is a 1 and the other a 0.

The whole optimization At each bit, let ones = count of numbers with a 1 and zeros = the rest. Every one-number pairs with every zero-number, so that bit contributes ones × zeros. Sum over all 31 bits — done in O(31·n) = O(n).

It's Σpairs Σbits = Σbits Σpairs — the same total, counted in a smarter order.


Two teams, count handshakes

At one bit, the numbers split into a "1" team and a "0" team. Every cross-team handshake is a differing pair: ones × zeros, and no same-team handshake counts.

Tally columns, not rows

Line the numbers up in binary and read down each column. One column's answer needs only its count of 1s — the rows (the actual numbers) stop mattering.

Contribution, not construction

Don't build each pair and score it. Ask how much each bit contributes to the grand total, and add those up. The pairs are never enumerated.


04 · Read down the columns

Each bit splits into ones and zeros

Enter numbers and step bit by bit. The current column highlights: 1-cells teal, 0-cells terracotta. The meters show that column's ones, zeros, its ones × zeros contribution, and the running total. Every other column dims so you can see one handshake-count at a time. Click any column header to jump to it.

Bit-column counter

ones (this bit)
–
zeros (this bit)
–
ones × zeros
–
running total
0

Try 7 7 7 (every column all-same → every contribution 0) or 0 7 (three columns of 1×1 → total 3). The grid shows only the bits actually used.


05 · Trace table

[4, 14, 2] one bit at a time

bit column (4,14,2) ones zeros ones × zeros
0 0, 0, 0 0 3 0
1 0, 1, 1 2 1 2
2 1, 1, 0 2 1 2
3 0, 1, 0 1 2 2

Total = 0 + 2 + 2 + 2 = 6 — and the three individual Hamming distances (4,14)=2, (4,2)=1, (14,2)=3 were never computed. Every differing bit of every pair got counted exactly once, in column order.


06 · The code

Two loops, but 31 is a constant

int totalHammingDistance(int[] nums) {
    int n = nums.length;
    long total = 0;
    for (int bit = 0; bit < 31; bit++) {
        int ones = 0;
        for (int num : nums)
            ones += (num >> bit) & 1;        // count 1s in this column
        total += (long) ones * (n - ones);  // ones × zeros
    }
    return (int) total;
}
Why (long) before the product
ones × zeros can exceed int
For large n the product overflows 32 bits. Cast first so the multiply happens in long.
Why 31 bits
10⁹ < 2³⁰
Non-negative values below 10⁹ fit in bits 0–30. 31 iterations covers them safely.

O(31·n) = O(n) time, O(1) space. A one-pass variant tallies an int[31] of column counts first, then sums the products — same complexity, counts each number's bits once.


07 · Why it's correct

ones × zeros, and no divide-by-two

The reordering Total = Σpairs Σbits differ(i,j,b). Since bits are independent, swap the sums to Σbits Σpairs. At a fixed bit, a pair contributes iff one endpoint is a 1 and the other a 0 — there are exactly ones × zeros such pairs.

No /2 is needed: the two endpoints come from disjoint groups, so each unordered pair is generated once (A from ones, C from zeros gives A–C, never also C–A). That's different from C(ones,2), which would count same-bit pairs — the opposite of what Hamming distance wants.


08 · Traps to avoid

Five ways it slips

Enumerating all pairs

The nested i,j loop is O(n²). If the score decomposes by bit, count each bit's contribution globally instead.

C(ones,2) + C(zeros,2)

That counts pairs that agree. Hamming wants pairs that differ — the cross product ones × zeros, no halving.

XOR-ing all numbers

A single fold a^b^c… loses the per-bit counts. Arrays with equal total XOR can have different pairwise totals.

Total set-bit count only

Knowing how many 1s overall isn't enough — you need the count per bit position. Keep the columns separate.

int overflow on the product

ones × zeros and the running total can pass INT_MAX. Accumulate in long, cast once at the end.


09 · The pattern

Sum over all pairs? Count contribution, don't build pairs

When a problem asks for a sum of some property over every pair and that property decomposes into independent components (here, bits), swap the order of counting: for each component, count how many pairs it contributes to. Quadratic pair enumeration collapses to O(B·n) with B a small constant.

Pairwise XOR sum
bit set when they differ
contribution = ones × zeros × 2ᵇ
Pairwise AND / OR sums
AND: both 1 · OR: not both 0
C(ones,2) · totalPairs − C(zeros,2)

Three questions unlock the whole family: can the score split into independent components? For one component, what makes a pair contribute? Can I count those pairs without listing them? Here: bits, differing bits, and ones × zeros.


10 · One month from now

Reconstruct it, don't memorize it

  1. Hamming distance = differing bits = set bits of a XOR b; I need the sum over all pairs.
  2. Pairwise enumeration is O(n²) — instead, fix a bit and count across all numbers.
  3. At each bit the numbers split into ones and zeros; a pair differs iff it straddles the split.
  4. So that bit contributes ones × zeros (disjoint groups → no divide-by-two).
  5. Sum over all 31 bits in long. O(n) time, O(1) space.
The transferable insight When you're summing a property over every pair, change the order of counting: go component-first and count contributing pairs directly, instead of building each pair. That's what turns quadratic bitwise problems into linear ones.