Bit manipulation — the tricks worth memorizing
📖 Walk me through it — plain English
Computers store every number as a row of bits — tiny on/off switches, written as 1s and 0s. The number 13, for example, is 1101 in this on/off form (that's 8 + 4 + 0 + 1). "Bit manipulation" just means flipping or comparing those switches directly instead of doing ordinary arithmetic. It feels like a magic trick the first time, but there are only about six patterns to learn, and then a whole class of problems becomes easy.
The star of this lesson is XOR, written ^. XOR compares two numbers bit by bit and outputs a 1 wherever the two bits differ, and 0 wherever they're the same. Two facts fall out of that rule and do all the work: any number XOR'd with itself is 0 (every bit matches itself, so every output bit is 0), and any number XOR'd with 0 is unchanged. So XOR is like a light switch: flip it with the same value twice and you're back where you started.
The classic problem ("Single Number") is: you're given a list where every value appears exactly twice except one loner that appears once. Find the loner. The trick: XOR every value in the list together. Each pair cancels itself out to 0 (because x ^ x = 0), and the leftover loner gets XOR'd against 0, so it survives untouched. Order doesn't even matter.
Analogy: imagine everyone at a party pairs up to leave, except one person with no partner. If you "cancel out" each matched pair as they walk out the door, whoever is still standing at the end is the single one. XOR is the bouncer doing that cancelling automatically.
Why it works: every paired value gets XOR'd in twice, and XOR'ing the same value twice returns to the starting state (the two flips on each bit undo each other), so all pairs vanish to 0. The single value is XOR'd in once against that 0, so it passes through unchanged. We touch each element exactly once and keep just one running number, so it runs in O(n) time (n = list length) and O(1) extra space — no hash set or sorting needed.
The lesson's other snippet, popcount, counts how many bits are set to 1. Its engine is n & (n - 1), which erases the lowest 1-bit each time. So you loop, stripping off one 1-bit per pass, and count the passes — the loop runs only as many times as there are 1-bits, which is faster than checking all 32 positions.
Bit problems look obscure until you know ~6 tricks. After that they're free points.
n | (1 << k) sets it, n & ~(1 << k) clears it, (n >> k) & 1 reads it.
def single_number(nums):
out = 0
for v in nums:
out ^= v # pairs cancel; the loner survives
return out
def popcount(n):
cnt = 0
while n:
n &= n - 1; cnt += 1
return cnt
function singleNumber(nums: number[]): number {
let out = 0;
for (const v of nums) out ^= v;
return out;
}
// JS note: bitwise ops force 32-bit signed int. For values > 2^31, use BigInt.
The classic XOR trick — write it and run it live: