A pruned backtracking search must run inside a request latency budget — how do you decide whether it can ship?
answer
- pruning helps which case exactly
- find the input where nothing prunes
- many cheap items, generous cap
- bound the work, do not just measure it
- what do you return at the cap
basics
~20 sPruning improves the average case, never the exponential worst case, so measurements on today's traffic cannot promise a latency bound. Ship only behind a bounded input size, a hard node budget with a defined fallback answer, and alerting on cap-hits.
solid answer
~50 sStart by refusing the premise that good pruning makes the search safe: a prune deletes subtrees on the inputs where the bound bites, and there are always inputs where it does not — a catalogue of items priced well under a generous cap prunes almost nothing and pays the full exponential walk. So the decision is not "is it fast enough?" but "what bounds the work?". Three controls make it shippable: cap the input (measure nodes visited against catalogue size and set the limit where the curve is still flat), cap the search itself (a node budget or deadline, with the best bundle found so far returned and flagged as approximate), and make the cap observable so you learn how often users hit it. Then make the real call: whether an exact exponential answer is worth more to the product than a polynomial approximation the team can reason about.
go deeper
Remember the headline: pruning cuts branches on many inputs but never lowers the worst case, so an exhaustive search still needs a limit on how much input it accepts.
Be able to construct the input where the prune never fires — cheap items under a generous cap — and explain why average-case speed is not a latency guarantee.
Show the controls you would actually build: a measured input bound, a node budget, a designed fallback answer, and a cap-hit metric that tells you when the bound has gone stale.
Own the trade between an exact exponential search behind guardrails and a well-behaved approximation, including who maintains it, what the product promises, and what breaks at ten times the catalogue.
## The claim to challenge first "With good pruning it's basically polynomial" is the sentence this question exists to catch. It is wrong in a specific and important way. Pruning removes subtrees **when the bound proves them hopeless**. Big-O is an upper bound over *all* inputs, and the input on which the bound never fires still exists. A pruned search is a faster exponential search: better constant, dramatically better average case on realistic data, identical worst case. The practical form of that distinction: benchmarks on production traffic tell you about the inputs you have seen. They say nothing about the input a user will submit tomorrow, and nothing at all about an input an adversary will submit deliberately. ## Find the shape that defeats the prune Before any latency conversation, characterise the bad input concretely. For a budget-capped bundle builder over a gift catalogue, the pruning test is "running total over budget — stop". It fires early when items are expensive relative to the cap. It therefore *fails* when: - items are priced far below a generous cap, so almost every partial selection stays feasible and the search walks nearly the whole tree; - prices cluster tightly, so the bound is nearly the same on every branch and gives no discrimination; - the catalogue is large, since the tree doubles with every additional item. And now notice that this is not an exotic shape. "Cheap items, generous budget, big catalogue" is a *good customer* — the search collapses precisely on the traffic you most want. That is the argument that moves a room: the worst case is not adversarial here, it is aspirational. ## The three controls **1. Bound the input.** Plot nodes visited against catalogue size on realistic price distributions, including the bad shape above. Set the accepted input size where the curve is still flat, with headroom, and reject or narrow beyond it — filters, categories, a required price floor. This is a product conversation, not a technical one: "we search up to 30 candidate items; past that we ask you to narrow the selection" is a shippable sentence. **2. Bound the search.** Even inside the input cap, carry a hard **node budget** or deadline in the recursion and stop when it is exhausted. What you return at that point must be designed, not accidental: the best bundle found so far, explicitly marked approximate, is usually right; an error that invites an identical retry is usually wrong. Prefer counting nodes over checking a clock — node counts are deterministic and therefore reproducible in tests, while wall-clock caps make failures depend on which machine ran them. **3. Make it observable.** Emit the node count per request and a counter for cap-hits. Without that you cannot tell a search that finished early from one that finished exactly, and you will not notice the day a catalogue change moves the whole distribution. The cap-hit rate is the metric that tells you whether the input bound is still right. ## The judgement that is actually yours With the controls in place, the remaining decision is about worth, not about speed: - **What is exactness worth here?** If the product promises "the best bundle under your budget", approximations need disclosure. If it promises "some good bundles", a greedy or value-density heuristic runs in near-linear time and may be indistinguishable to the user. - **What is the cost of the alternative?** A pseudo-polynomial dynamic program may exist for the exact same objective and be dramatically better behaved on large catalogues, at the cost of memory proportional to the cap and a structure fewer people on the team can debug at 3am. Ask who maintains it. - **Does it belong on the request path at all?** Precomputing bundles per category overnight, or caching by the tuple of filters, converts a latency problem into a freshness problem — often the better trade for a catalogue that changes daily rather than per request. - **What breaks at ten times the catalogue?** If the answer is "the search doubles thirty more times", say that plainly. A control that only holds at today's scale is a dated decision, and it should be written down with the date on it. ## The one-sentence version to have ready "It prunes well on our data, the worst case is still exponential, so it ships behind an input cap and a node budget with a documented fallback — and we revisit when cap-hits exceed a threshold or the catalogue grows past the size we measured." That sentence contains the correction, the controls, the fallback and the trigger to reconsider, which is the whole of the judgement.
- Why cap on nodes visited rather than on elapsed time?A node budget is deterministic: the same request explores the same number of nodes on any machine, so the cap is reproducible in tests and the fallback path can be exercised deliberately. A wall-clock deadline drifts with load, hardware and warm-up, so failures appear and vanish unpredictably. In practice you often carry both — nodes as the contract, a clock as a backstop against a pathological per-node cost.
- How do you decide the accepted input size?Measure nodes visited against catalogue size across price distributions, including the one where nothing prunes — cheap items under a generous cap. Set the limit where that worst curve is still flat, with headroom, then express it as a product rule rather than an error: narrow by category or price band beyond it. Re-measure when the catalogue's price distribution shifts, not on a fixed schedule.
- When would you argue against the exhaustive search entirely?When the product does not need optimality, when the input bound would have to be so tight that it changes the feature, or when a well-understood alternative gives a bound the team can reason about. Also when the work can move off the request path — precomputed or cached results per filter combination turn a latency risk into a freshness policy, which is usually easier to operate.
saying these in an interview costs you the question
- Says good pruning makes the search effectively polynomial
- Promises a latency bound from benchmarks on typical traffic
- Adds a timeout with no defined answer at the timeout
- Never identifies the input shape on which nothing prunes
- Treats the exponential worst case as purely theoretical