Expert: advanced patterns and interviews · Tries, union-find and bit manipulation · topic 51 of 61 · 35 min
Bit tricks in interviews
Explanation
Three rules of XOR
- x ^ 0 = x: XOR with 0 changes nothing.
- x ^ x = 0: a number XOR itself cancels out.
- Order does not matter: a ^ b ^ c is the same in any order and any grouping.
Together they mean: if you XOR a list in which every value appears twice except one, all the pairs cancel and only the lonely value remains.
Single number
Problem: every number in a list appears exactly twice, except one. Find it. A dictionary of counts works in O(n) time but uses O(n) extra space. XOR-ing everything gives the answer in O(n) time and O(1) extra space.
from functools import reduce
from operator import xor
nums = [4, 1, 2, 1, 2]
print(reduce(xor, nums, 0)) # Output: 4Missing number
Problem: a list holds n different numbers from 0 to n, so exactly one is missing. The sum way: the numbers 0..n add up to n(n + 1)/2, so the missing one is that total minus sum(nums). The XOR way: XOR all of 0..n together with all of nums; every present number appears twice and cancels, leaving the missing one. In Python the sum cannot overflow, but in languages with 32-bit ints a big sum can, while XOR never does.
All subsets with bitmasks
A set of n items has 2ⁿ subsets. Number them with masks from 0 to 2ⁿ − 1, that is range(1 << n). In mask, bit i says whether item i is in the subset. Counting through the masks lists every subset exactly once, with no recursion. The cost is O(n × 2ⁿ), the same as backtracking (Module 5), because the output itself has that size. It is practical only for small n, about 20 or less.
items = ["a", "b", "c"]
n = len(items)
for mask in range(1 << n):
subset = [items[i] for i in range(n) if mask & (1 << i)]
print(f"{mask:03b}", subset)
# Output:
# 000 []
# 001 ['a']
# 010 ['b']
# 011 ['a', 'b']
# 100 ['c']
# 101 ['a', 'c']
# 110 ['b', 'c']
# 111 ['a', 'b', 'c']Hamming distance
The Hamming distance between two numbers is the number of bit positions where they differ. XOR puts a 1 exactly where the bits differ, so the distance is the popcount of x ^ y. It is used in error-detecting codes and for comparing short "fingerprints" of files or images.
Gray code in one line
In a Gray code sequence, neighbouring numbers differ in exactly one bit. The i-th Gray code is i ^ (i >> 1): for i = 0, 1, 2, 3 it gives 0, 1, 3, 2, which is 00, 01, 11, 10. Rotary position sensors use Gray codes so that a reading taken between two positions is never wildly wrong.
Swapping without a temporary variable
a, b = 5, 9
a ^= b
b ^= a
a ^= b
print(a, b) # Output: 9 5This XOR swap is a nice puzzle but a bad habit in real code. It is harder to read, it is usually no faster on modern hardware, and if both names refer to the same memory location (for example swapping arr[i] with arr[j] when i == j), it sets the value to 0.
Preview: bitmask dynamic programming
A mask can also stand for "which items have I used so far". For example, the cheapest tour through n cities can be solved with a table indexed by (mask of visited cities, current city) in O(2ⁿ × n²) time, which is practical for n up to about 20. Module 11 covers dynamic programming.
Common mistakes
- Using the XOR trick when the other numbers appear three times. Pairs cancel; triples do not. Fix: count bits per position modulo 3, or use a dictionary.
- Writing mask & i instead of mask & (1 << i) when testing bit i. Fix: always build the mask with a shift.
- Writing 2 ^ n for 2ⁿ. Fix: 1 << n or 2 ** n.
- Hamming distance with negative numbers in Python: x ^ y can be negative, and bin() then hides the bit pattern. Fix: keep inputs non-negative, or mask both with & 0xFFFFFFFF.
- Using XOR swap on two names that may refer to the same element. Fix: use a normal swap.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Bit tricks in interviews · 1/8
This lesson collects the bit tricks that interviewers love, starting with XOR.
Prefer a video by a teacher? Find free videos on “bit manipulation interview problems single number missing number subsets bitmask” on YouTube ↗
In real life: Spotting near-duplicate photos
Photo apps and content platforms often need to spot images that are almost the same, such as the same photo resized or slightly brightened. A common approach turns each image into a short "perceptual hash", a number whose bits describe the rough light and dark pattern of the picture. Similar images get hashes that differ in only a few bits, so the Hamming distance (popcount of XOR) is a fast similarity test. Real systems use 64-bit or longer hashes and tuned thresholds; the 16-bit values below are made up.
h1 = 0b1011_0110_1100_0011
h2 = 0b1011_0100_1100_0111
h3 = 0b0100_1001_0011_1100
print(bin(h1 ^ h2).count("1")) # similar photos
print(bin(h1 ^ h3).count("1")) # different photosPractice (0/4 done)
Write single_number(nums). Every value in nums appears exactly twice, except one value that appears once. Return that value. Use XOR: O(n) time and O(1) extra space (no dictionary or set). Values may be negative. Example: single_number([4, 1, 2, 1, 2]) returns 4.
Write missing_number(nums). nums holds n DIFFERENT numbers taken from 0, 1, …, n, so exactly one number in that range is missing. Return it. O(n) time, O(1) extra space: use XOR (or the sum formula). An empty list means n = 0, so the missing number is 0. Example: missing_number([3, 0, 1]) returns 2.
Write subsets_bitmask(nums) that returns ALL subsets of nums as lists, using bitmasks. Order the subsets by mask from 0 to 2ⁿ − 1, where bit i of the mask means nums[i] is included, and keep the items of each subset in their original order. Treat items at different positions as different even if equal. Example: subsets_bitmask([1, 2, 3]) returns [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]].
Write hamming_distance(x, y) for x, y ≥ 0. Return the number of bit positions where x and y differ. Hint: XOR them, then count the 1 bits. Example: hamming_distance(1, 4) returns 2, because 001 and 100 differ in two places.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Minimum spanning treesTries, union-find and bit manipulation · same module
- Union-find (disjoint set union)Tries, union-find and bit manipulation · same module
- Knapsack problemsDynamic programming
- Bitwise operatorsC Programming (from zero to systems) · Bits, undefined behaviour and safety
- More DP patterns and how to spot themDynamic programming
- Subnet masks, prefix length and wildcard masksComputer Networking (CCNA level) · IPv4 addressing
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What is 7 ^ 3 ^ 7?
Answer: 3
The two 7s cancel, leaving 3.
Why might XOR be preferred over the sum formula for "missing number" in Java or C++?
Answer: A big sum can overflow a fixed-size int; XOR cannot
n(n + 1)/2 can exceed 32 bits; XOR results never grow beyond the inputs' width.
How many masks do you loop over to list every subset of 4 items?
Answer: 16
2⁴ = 16 masks: 0 to 15.
Items are [a, b, c] and bit i stands for item i. Which subset does mask 5 (binary 101) mean?
Answer: [a, c]
Bits 0 and 2 are set, so items 0 and 2: a and c.
What is the Gray code i ^ (i >> 1) for i = 3?
Answer: 2
3 is 11, 3 >> 1 is 01, and 11 XOR 01 = 10 = 2.
Why avoid the XOR swap in real code?
Answer: It is harder to read, and it sets the value to 0 if both names are the same element
a ^= a gives 0, so swapping an element with itself destroys it.
Why does "while n: n >>= 1" never end for n = −1 in Python?Related
Answer: -1 >> 1 is still -1
Right-shifting a negative Python int rounds down, so −1 stays −1 forever.
How many subsets does a set of 6 distinct items have?Related
Answer: 64
Each item is in or out: 2⁶ = 64, including the empty set.
Target sum: numbers [1, 1, 1, 1, 1], target 3, each with + or −. Which subset sum P do you count?Related
Answer: P = 4
P = (total + target) / 2 = (5 + 3) / 2 = 4. There are 5 ways to choose four 1s.
From Knapsack problems
Why use unsigned types for bit manipulation?Related
Answer: Shifts and overflow are well defined for unsigned types
Signed shifts have implementation-defined or undefined cases.
From Bitwise operators
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- This is the last topic of “Tries, union-find and bit manipulation”. The module exam comes next.
- Module 10 exam: Tries, union-find and bits · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Dynamic programming. 61 topics left in the course before the final exam.