skip to content

At a billion implicit states, what breaks first in a state-space search, and what would you trade away?

level: principalimportance: nice to knowfreq 28%

answer

  1. Count the bytes before choosing a technique
  2. Generation is cheap; remembering is not
  3. Two frontiers instead of one
  4. Memory can be traded for time, I/O or exactness
  5. Approximate skipping is a correctness decision

basics

~20 s

The visited set breaks first. Generating neighbors stays cheap per state, but remembering a billion of them costs gigabytes even at eight bytes each, so the real decision is what you give up: memory, recomputation, exactness or scope.

solid answer

~50 s

Neighbor generation is not the problem — a handful of arithmetic per state, linear in what you explore. The visited set is what dies: a billion states at an eight-byte fingerprint is 8 GB before container overhead, and the frontier adds more. So I attack the model first — drop fields that do not change which moves are legal, and normalize symmetric states, which can shrink the set several-fold for a small per-state cost. Then the structural win: bidirectional search replaces one frontier of size b^d with two of roughly b^(d/2), when the target is known and moves invert. Only then the uncomfortable trades — depth-limited iterative search that holds memory proportional to depth and pays by regenerating shallow states, external-memory search that batches duplicate removal on disk, or an approximate filter whose false positives can skip a reachable state. That last is a correctness decision, and it needs an owner.

go deeper

for a junior

Know that a search must remember where it has been, and that this memory grows with the number of states explored rather than with the size of the code.

for a middle

Be able to convert a state count into bytes: a fingerprint per state times a billion is gigabytes before container overhead, which is why the visited set fails before neighbor generation does.

for a senior

Show the ladder in order: shrink the state, normalize symmetry, fingerprint, go bidirectional, then trade memory for time or I/O. Explain what each trade costs and when it applies.

for a principal

Own the promise the system makes. Decide whether an exact answer is required before allowing an approximate filter, weigh a maintainable capped search against a clever disk-backed one, and say who carries the result.

## Locate the bottleneck before choosing a technique The reflex answer to "it is too slow at scale" is to optimize the inner loop. In implicit-graph search that is the wrong end. Neighbor generation is a few additions and bounds tests per state — cheap, cache-friendly, and linear in the states you actually expand. What grows without bound is **memory for the states you must remember**: the visited set, plus the frontier of states discovered but not yet expanded. Do the arithmetic out loud, because it is the whole argument. A billion states with a 64-bit fingerprint each is 8 GB of payload. A general-purpose hash-based set typically adds 50-100% overhead in slots, pointers and load-factor slack, so plan on 12-20 GB. Store the state itself rather than a fingerprint — a board arrangement, a coordinate plus an inventory — and it can be several times that again. Meanwhile the frontier at the widest level of a breadth-shaped search can itself hold a large fraction of a level's states. ## The ladder of responses, cheapest first **1. Shrink the state.** The most valuable question is whether every field in the state actually changes which moves are legal or whether the goal is met. Fields carried "for reporting" belong outside the key. This costs nothing and sometimes collapses the space by orders of magnitude. **2. Exploit symmetry.** If eight arrangements are the same situation viewed differently, normalize to one representative and the set shrinks nearly eightfold, paying a canonicalization cost per state. Whether that trade is good depends on whether canonicalization is cheaper than the memory it saves — usually yes, and it is exact, which makes it the last free lunch on the ladder. **3. Fingerprint instead of storing.** Hash each state to a fixed-width value and store that. This is smaller and uniform, but it introduces a real if tiny collision risk: two distinct states sharing a fingerprint means one is wrongly skipped. At a billion states a 64-bit fingerprint makes that risk negligible; a 32-bit one makes it near-certain, which is a calculation worth doing rather than assuming. **4. Halve the depth.** Bidirectional search grows a frontier from the start and another from the target. With branching factor b and solution depth d, one frontier is on the order of b^d while two are on the order of b^(d/2) — the single biggest structural win available. It requires knowing the target state explicitly and being able to invert moves, and it needs care where the two frontiers meet. Not every problem qualifies; when yours does, it beats every memory trick below. **5. Trade memory for time.** Depth-limited iterative deepening keeps only the current path, so memory is proportional to depth rather than to states. The price is regenerating the shallow levels on every round; with a branching factor comfortably above 1 the repeated work is a constant factor, because the deepest level dominates the total. Without a visited set it also re-derives states reached by different paths, which on a densely reconverging graph is far worse than the clean analysis suggests. **6. Trade memory for I/O.** External-memory search writes the frontier to disk in batches, sorts each batch, and removes duplicates by merging — deferring deduplication instead of doing it per state. This is how genuinely enormous puzzle spaces get searched. It is a real engineering project with real operational surface, and that is the point at which the decision stops being algorithmic. **7. Trade exactness.** An approximate membership filter uses a few bits per state. Its errors run one way: it may claim a never-visited state has been seen. That state is then skipped, and with it everything reachable only through it — so the search can miss a solution it should have found. That is a correctness trade, and it belongs to whoever owns the promise the system makes to its users, not to whoever is tuning it. ## The judgment, which is the actual question An interviewer asking this at a senior level wants the ladder. Asking it at a lead level wants the framing around it: *what does the product actually promise?* If the answer must be provably optimal — a safety interlock, a billing computation — options 6 and 7 are off the table and the honest recommendation may be to constrain the problem instead: cap the search depth and report failure, prune with a domain heuristic, or precompute answers for the small set of queries that really occur. If a good answer within a latency budget is sufficient, an approximate filter or a bounded search may be exactly right, and the engineering saved is real. There is a maintenance dimension too. An external-memory search with batched duplicate removal is perhaps twenty times the code of the straightforward version and needs someone who understands it at 3 a.m. A team that cannot carry that should not be handed it as a clever optimization; the cheaper honest move is often to shrink the state, cap the depth, and revisit when the constraint actually bites. Naming that tradeoff — the cost of the clever structure against the cost of the slow one — is what separates this answer from a list of techniques.

  • How much does normalizing symmetric states actually buy?
    Roughly a division by the size of the symmetry group: a board with eight equivalent orientations shrinks the visited set close to eightfold. The cost is computing a canonical form on every state, which is usually far cheaper than the memory saved. It is also exact, unlike approximate filtering, which makes it the first structural saving to reach for.
  • When would you refuse an approximate visited set outright?
    When the system promises a definitive answer. False positives skip states and can hide a reachable solution, so anything that must be provably complete — a safety interlock, a compliance check, a settlement calculation — cannot use one. If the promise is only a good answer inside a latency budget, the filter is defensible, provided the error rate is measured and stated rather than assumed.
  • Your team cannot maintain an external-memory search. What do you recommend instead?
    Constrain the problem before building the machine. Shrink the state, normalize symmetry, cap the search depth and report failure honestly, or precompute results for the narrow set of queries that actually occur. Those are all reversible and readable. A disk-backed search with batched duplicate removal is many times the code and needs an owner at 3 a.m.; buy it only when the constraint genuinely bites.

saying these in an interview costs you the question

  • Optimizes neighbor generation while the visited set is the bottleneck
  • Quotes state counts without converting them to bytes
  • Treats an approximate visited filter as a free win
  • Proposes bidirectional search without an explicit target state
  • Ignores who will maintain the disk-backed search

context