Coding Interview Patterns Module 17 – Bit manipulation
Bitsets: subset sums by shifting
Decide whether parcels can fill a truck exactly or split evenly between two, with every reachable load kept as one bit: the problems and the brute force.
What you will learn
- Represent the reachable sums as the bits of one integer and add an item with a shift and an OR
- Prove that reach | (reach << w) adds one item to every reachable sum
- Estimate and measure the speed-up of a bitset over a boolean table
- Use Python integers, Java long[] words, std::bitset, Go words and JavaScript BigInt as bitsets
- Avoid the word-boundary and shift-count traps of a hand-written bitset shift
Before you start
What you’ll learn · Before you start
What you will learn
- Represent the reachable sums as the bits of one integer and add an item with a shift and an OR
- Prove that reach | (reach << w) adds one item to every reachable sum
- Estimate and measure the speed-up of a bitset over a boolean table
- Use Python integers, Java long[] words, std::bitset, Go words and JavaScript BigInt as bitsets
- Avoid the word-boundary and shift-count traps of a hand-written bitset shift
Before you start
On this page
A bitset keeps a set of small integers as the bits of one long integer, or of an array of machine words, so a whole set can be shifted, combined or tested in a few word operations. Subset sums are the classic use: keep every load that some group of items can make as a 1 bit, and adding an item of weight w moves every load up by w at once, a shift. That replaces a table of n × C booleans with n shifts of C bits, 64 bits a step on a 64-bit machine and much more than that in Python, where a big-integer shift runs in C. Here are the problems, their brute force with its cost, and what to notice.
Two loading problems
Problem A: fill a truck exactly. A courier hub has n ≤ 200 parcels of whole-kilogram weights from 1 to 2,000.
Can some of them weigh exactly C kilograms, for a truck of capacity C ≤ 2 × 10⁵? With the parcels [3, 1, 4, 2, 2],
C = 6 gives yes and C = 13 gives no, because all five together weigh only 12.
Problem B: split evenly. Can all the parcels go onto two trucks that carry exactly the same weight? [3, 1, 4, 2, 2] gives yes, with 4 + 2 on one truck and 3 + 1 + 2 on the other; [5, 3] and [1, 2, 5] give no.
An even split, and a load that no group reaches
Text description of the diagram
The upper panel shows the parcels 3, 1, 4, 2 and 2, which weigh 12 kg together. Truck 1 takes the parcels 4 and 2, and truck 2 takes 3, 1 and 2, so each carries 6 kg.
The lower panel shows the parcels 1, 2 and 5, which weigh 8 kg together, so each truck would need exactly 4 kg. A row of nine cells, one for each load from 0 to 8 kg, holds a 1 where some group of the parcels weighs exactly that much: 0, 1, 2, 3, 5, 6, 7 and 8 have a 1, and 4 has a 0. No group weighs 4 kg, so no even split exists. The row of 0s and 1s is the set of reachable loads.
The brute force, and why it fails at these sizes
Trying every group of parcels answers both questions, and nobody doubts it:
# Both problems by brute force: try every subset of the parcels and add up its weight.
from itertools import combinations
def fills_exactly_brute(weights, capacity):
"""Problem A: does some subset weigh exactly capacity? Returns the answer and the subsets tried."""
tried = 0
for k in range(len(weights) + 1):
for subset in combinations(weights, k):
tried += 1
if sum(subset) == capacity:
return True, tried
return False, tried
def splits_evenly_brute(weights):
"""Problem B: can the parcels go into two trucks of exactly equal weight?"""
total = sum(weights)
return total % 2 == 0 and fills_exactly_brute(weights, total // 2)[0]
print("A:", fills_exactly_brute([3, 1, 4, 2, 2], 6), " ([3, 1, 4, 2, 2], capacity 6)")
print("A:", fills_exactly_brute([3, 1, 4, 2, 2], 13), " (capacity 13)")
for weights in ([3, 1, 4, 2, 2], [5, 3], [1, 2, 5]):
print("B:", weights, "->", splits_evenly_brute(weights))
print(f"at n = 200 there are 2^200 = {2**200:.3e} subsets") Output
A: (True, 14) ([3, 1, 4, 2, 2], capacity 6) A: (False, 32) (capacity 13) B: [3, 1, 4, 2, 2] -> True B: [5, 3] -> False B: [1, 2, 5] -> False at n = 200 there are 2^200 = 1.607e+60 subsets
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 brute_force.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
Five parcels have 32 groups. Two hundred have 2²⁰⁰, about 1.6 × 10⁶⁰, more than any computer will ever enumerate. The usual repair is a table of booleans, one row per parcel and one column per load from 0 to C, which needs 200 × 200,001 = 40,000,200 cells at the limits: fine in C++, slow in Python, and still one cell at a time.
What to notice
- The answers are a set of small integers: the loads from 0 to C that some group reaches. A set of small integers fits in the bits of one big number, bit s for load s.
- Adding a parcel of weight w keeps every load and adds every load plus w, the same operation on every member of the set: a shift of the whole set by w, combined with the set itself.
- Problem B is problem A with C equal to half the total, after checking that the total is even.
Reachable loads as bits: reach | (reach << w), proved Pro: opens with a Pro, Premium or Ultimate pass
In this part:
- The table it replaces, and the speed-up worked out
- Measured: a boolean table against a Python integer
- The code in five languages
- A word shift that breaks only for multiples of 64
- Edge cases and common bugs
- Variants: the closest split, distinct loads and repeated parcels
- Exercise: two equal loads
- Split parcels into two equal loads with a bitset
- A practice set with sample answers
- Check yourself
- Interview questions
- In a subset-sum bitset, what does reach |= reach << w do, and why is the answer bit C at the end?
- Your Java subset-sum keeps the reachable sums in a long[] and shifts it by hand. It passes every test until one with a parcel of exactly 64 kg, where it reports loads that no group makes. What is wrong, and what would the same code do in C++ and in Go?
- A teammate wants a subset-sum bitset for three tasks: 40 items with weights up to 10^12 and one target; the number of groups that reach a target, modulo 10^9 + 7; and 10,000 items with weights up to 1,000 and targets up to 10^6. Which fit, and what would you use for the others?
- Before coding, estimate the time and memory of an equal-split check for 2,000 items whose total is at most 4 × 10^6, first with a boolean table and then with a bitset of 64-bit words. Would each pass a 1-second limit in C++?
- Key takeaways
8 runnable examples (C++, Go, Java, JavaScript, Python) · 1 exercise with sample tests · 3 interview answers · about 21 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
References
- Bitwise operations on integer types (The Python Standard Library: built-in types) (Python Software Foundation)
- Java SE 25 API: java.util.BitSet (Oracle)
- The Java Language Specification, Java SE 25: 15.19 Shift operators (Oracle)
- std::bitset (cppreference.com) (cppreference.com)
- Arithmetic operators: bitwise shift operators (cppreference.com) (cppreference.com)
- The Go Programming Language Specification: arithmetic operators and shifts (The Go Authors)
- ECMAScript language specification: the BigInt type (Ecma International (TC39))
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress