skip to content

When should a telemetry API promise any local peak in O(log n) instead of the global maximum?

level: principalimportance: nice to knowfreq 22%

answer

  1. different cost, or different question?
  2. what does the consumer mean by peak?
  3. is the input guaranteed single-humped?
  4. the fast answer is not a stable answer
  5. measure before trading away a guarantee

basics

~20 s

Promise a local peak only when consumers genuinely need a point where the climb stops and the input is guaranteed single-humped, so the two answers coincide. Promise the global maximum whenever results are compared, alerted on or reported.

solid answer

~50 s

Treat it as a contract decision, not a performance one. The logarithmic answer is *some* turning point; the linear scan is *the* maximum plus, for the same pass, the peak count and every other statistic anyone will ask for next quarter. Three questions decide it. Is the data guaranteed single-humped by the physics that produced it? If yes the two answers coincide and the cheap one is free. Does any consumer compare peaks across runs, alert on them, or bill from them? Then only the global maximum is defensible. Is the O(n) scan actually a problem — is n large enough, and the query rate high enough, that the difference leaves the noise floor? Also weigh a hidden cost: the logarithmic answer is not stable, so a probe-path change can return a different valid peak and silently move a downstream number. Name the endpoint after what it returns.

go deeper

for a junior

Know that the fast search returns some turning point while a full scan returns the largest reading, and that these are different promises rather than two speeds of the same one.

for a middle

Be able to say when the two coincide — a guaranteed single-humped series has exactly one local maximum — and to state the scan's cost honestly against the request's actual latency budget.

for a senior

Show you would quantify before trading a guarantee away, and that you know the fast answer is unstable across implementations, which makes pinned tests and derived metrics fragile.

for a principal

Own the contract: what the endpoint promises, where the input-shape guarantee is enforced, whether two clearly named operations beat one ambiguous one, and what the clever code costs the team that maintains it.

## The two contracts are not two speeds of one thing It is tempting to file this as "O(log n) versus O(n)" and pick the faster one. That framing is the mistake. The logarithmic slope-comparison search answers *"give me an index where the readings stop climbing"*. A linear scan answers *"give me the largest reading"*. These are different questions with different answers, and only one of them is what most consumers mean when they say "the peak". Choosing the cheap one is choosing to ship a weaker guarantee, so the decision belongs with whoever owns the contract, not with whoever is optimising the loop. ## When the cheap guarantee is genuinely free If the series is **guaranteed single-humped** — one ascent, one descent, by the physics of how it is produced, such as a climb-and-descent altitude profile for a single flight — then it has exactly one local maximum, and *any peak* is *the peak*. The two contracts coincide and the logarithmic search costs nothing in fidelity. The engineering work then moves upstream: where is that guarantee enforced? Options, in descending order of how well they age: 1. **In the shape of the data** — the ingest path only ever stores per-flight segments, each of which is single-humped by construction. 2. **Validated once at ingest** — an O(n) check when the series is written, amortised across every subsequent query. 3. **Assumed in a comment** — which is how you get a silently wrong number three quarters later, when someone starts concatenating two flights into one series and nothing complains. Per-query validation is the option that never makes sense: it costs the O(n) pass you were trying to avoid. ## When only the global maximum will do Any consumer that **compares** peaks — across flights, across time windows, against a threshold — needs the maximum, because comparing arbitrary local peaks compares noise. Alerting, capacity reporting and anything a customer sees are all in this bucket. So is anything that must be reproducible in an audit. If one consumer needs the maximum and others do not, expose two clearly named operations rather than one that is quietly the weaker of the two; a shared endpoint whose semantics are "whatever the fast path returns" is a defect waiting for its incident. ## Is the linear scan even a problem? Quantify before optimising. The relevant numbers are the series length, the query rate, and the latency budget. For a few thousand samples per series the scan is microseconds and the difference never leaves the noise floor of the network hop in front of it. The logarithmic search earns its keep in two situations that are worth naming explicitly: series large enough that a full pass dominates the request, and **series where reading a sample is itself expensive** — samples fetched over a network, decompressed per block, or computed on demand. In that second case the win is not asymptotic elegance, it is that you touch about log n samples instead of all of them, which is a real cost line. ## The stability trap The logarithmic answer is **not stable**. Two correct implementations — one probing the right neighbour, one the left; one flooring the midpoint, one not — return different valid peaks for the same input. That has three consequences a lead should anticipate: - Golden tests that pin a specific index become brittle for reasons unrelated to correctness, and get "fixed" by whoever is on call. - A downstream metric derived from the returned index can move without any data changing, purely because the search was refactored. That is the worst kind of production mystery: no input changed, and the diff looks harmless. - Caching and idempotency reasoning quietly weakens, because the same query can legitimately answer differently across versions. Mitigations, in order of preference: pick the stronger contract; or fix a documented tie-break rule (for example, always the leftmost qualifying peak) and test *that property* rather than one index; or document the non-determinism loudly at the API surface so consumers do not build on an accident. ## What the decision costs the team The last input is maintenance. The linear scan is three lines any reviewer verifies at a glance and extends for free when the next request arrives ("also give me the second-highest", "also the peak count"). The invariant-based search is correct for a reason that takes a paragraph to state, has a well-known infinite-loop mutation, and is the kind of code that gets subtly broken by a well-meaning refactor. If the measured win is small, the stronger contract and the simpler code are the same choice, which is usually the tell that it is the right one. ## How to say it in an interview Do not answer "logarithmic, obviously". Ask what the consumer means by peak, ask whether the input shape is guaranteed, ask whether the O(n) pass is actually on the critical path — then commit, and name the risk you accepted. The judgment being tested is whether you know that a cheaper algorithm can silently be a weaker promise.

  • The data is guaranteed single-humped today. How do you keep that from rotting?
    Push it into the shape of what you store — per-segment series that are single-humped by construction — or validate once at ingest, where the O(n) check is amortised over every later query. A comment stating the assumption is not enforcement; it fails silently the day someone concatenates two segments.
  • How do you test a function whose correct answer is not unique?
    Test the property, not the index: assert that the returned position is at least as large as its existing neighbours, over generated inputs including flat runs, single elements and edge peaks. Pinning one specific index couples the test to the probe path and breaks on refactors that changed nothing meaningful.
  • When is the logarithmic search clearly worth the weaker guarantee?
    When reading a sample is expensive rather than merely numerous — samples fetched over the network, decompressed per block, or computed on demand — because you touch about log n of them instead of all n. That is a real cost line, unlike a microsecond scan over an in-memory series.

saying these in an interview costs you the question

  • Picks the logarithmic option purely because it is faster
  • Treats 'a peak' and 'the maximum' as interchangeable
  • Never asks what the consumer does with the result
  • Assumes the input shape without saying who enforces it
  • Pins a specific returned index in golden tests

context