skip to content

questions

4

Why can an O(n log n) pass handle a billion log events when an O(n^2) pass cannot?

level: juniorimportance: must knowfreq 78%

answer

  1. put the real n into both formulas
  2. log base two of a billion is about thirty
  3. 3x10^10 steps versus 10^18 steps
  4. the ratio between them is n over log n
  5. faster machines buy constants, not exponents

basics

~20 s

At a billion events an O(n log n) pass takes roughly 3x10^10 steps, which is seconds. An O(n^2) pass takes 10^18 steps, about thirty years at a billion steps per second. The gap grows with n, so faster hardware never closes it.

solid answer

~40 s

Growth classes separate by factors that scale with the input, not by constant factors. At `n = 10^9`, an `O(n log n)` pass does about `n * 30 = 3x10^10` element operations — tens of seconds at a billion operations per second. The `O(n^2)` pass does `10^18` of them, roughly thirty years on the same machine. The ratio between the two is `n / log n`, about `3x10^7` at this size, and it keeps widening as the data grows. That is why hardware does not rescue the quadratic version: a machine 100 times faster buys back only a 10x larger input for quadratic work, because the feasible `n` scales with the square root of the speedup. Picking the better class is the only lever that moves with the data.

go deeper

for a junior

Be ready to substitute a concrete input size into each formula and convert the result to seconds out loud. Knowing that log base two of a billion is about 30 turns this from a memorised ordering into an argument you can defend.

for a middle

Explain the ratio, not just the ordering: quadratic work costs n/log n times more than linearithmic work, so the penalty itself grows with the data. Be able to say where a class leaves the feasible band as volume rises.

for a senior

Show that you plan capacity against growth curves rather than today's measurement. An interviewer expects you to catch the extrapolation error when someone benchmarks a quadratic step at small volume and declares it fine.

for a principal

Own the framing that compute budgets move constants while algorithm choice moves exponents. When a roadmap projects an order-of-magnitude growth, you decide which steps must change class and which are safe to leave alone.

## What a growth class actually claims A growth class names the **shape** of the curve that relates input size `n` to work done, with constant factors deliberately discarded. `O(n log n)` does not say "this takes `n log n` nanoseconds"; it says "double the input and the work grows a little more than double". `O(n^2)` says "double the input and the work quadruples". Because those statements are about *ratios*, the difference between two classes is itself a function of `n` — it is not a fixed multiplier you can buy your way out of. ## The ladder, with real arithmetic Assume one element operation per step and a machine doing `10^9` of them per second. Logarithms are base two, so `log2` of a billion is about 30. | n | O(log n) | O(n) | O(n log n) | O(n^2) | O(2^n) | |---|---|---|---|---|---| | 10^3 | ~10 | 10^3 | 10^4 (10 microseconds) | 10^6 (1 millisecond) | ~10^301 | | 10^6 | ~20 | 10^6 (1 ms) | 2x10^7 (20 ms) | 10^12 (~17 minutes) | beyond physical meaning | | 10^9 | ~30 | 10^9 (1 s) | 3x10^10 (~30 s) | 10^18 (~32 years) | beyond physical meaning | Read the last row across. The linear and near-linear classes stay inside a nightly batch window. Quadratic work leaves the feasible region entirely somewhere between a million and a billion elements: at `10^6` it is an uncomfortable seventeen minutes, at `10^9` it is a human lifetime. Exponential and factorial classes were never in the region at all — `O(2^n)` passes a billion steps by `n = 30` and passes the number of atoms in the observable universe well before `n = 300`. ## Why the ratio, not the difference, is the point Divide the two step counts: `n^2 / (n log n) = n / log n`. At a thousand elements the quadratic version does 100 times more work; at a million, 50,000 times more; at a billion, about 30 million times more. The penalty is not a property of the algorithm alone — it is a property of the algorithm **and the size you run it at**, and it grows without bound. Any argument of the form "the quadratic one is only a bit slower, we measured it" is a measurement at one `n` being extrapolated as if the gap were constant. It is not. ## Why hardware and parallelism buy so little A faster machine, more cores, or a bigger fleet multiplies your throughput by some constant `c`. For a quadratic algorithm, solving `n'^2 = c * n^2` gives `n' = n * sqrt(c)`: a hundredfold speedup raises the feasible input by only 10x, a thousandfold speedup by about 32x. For `O(n log n)` the same constant `c` raises the feasible input by very nearly a factor of `c`. And for exponential work the arithmetic is brutal — a thousandfold speedup buys about ten more elements of `n`, since `2^10` is roughly 1000. This is the single most useful consequence of the ladder for planning: **compute budgets move the constant, algorithms move the exponent.** If a nightly job is projected to grow 100x in volume, no procurement decision saves a quadratic step, but a change of growth class does. ## Reading the label honestly Three cautions belong with the ladder. First, `O` is an upper bound: an `O(n^2)`-labelled routine is *permitted* to be slower than linear, not obliged to be — the ladder tells you what you must plan for, not what you will always observe. Second, constants and lower-order terms are hidden, and they dominate at small `n`; this is exactly why real implementations often switch to a simple quadratic method for tiny inputs, where its lower overhead wins. Third, the classes describe a single dimension of cost — a pass that is asymptotically cheaper can still lose on memory traffic or on extra space, so "better class" means "better scaling", not "better in every respect". The junior-level skill being tested is simply the ability to put the real number in and read the answer out: name the class, substitute the `n` you actually have, convert to seconds, and say whether that fits the window you were given.

  • Would running that O(n^2) pass across a thousand machines make it feasible?
    No. Parallelism divides by a constant: `10^18 / 1000` is still `10^15` operations, about eleven days of wall clock even with perfect scaling and no coordination cost. Put differently, a thousandfold increase in compute raises the input a quadratic step can absorb by only about 32x, because feasible `n` grows with the square root of the speedup. The fleet changes the constant; only a different growth class changes the curve.
  • At a billion events, is choosing O(n) over O(n log n) worth agonizing over?
    Usually not the same way. The factor between them is `log n`, about 30 here — real, and worth having if a nightly window is tight, but both sit inside the feasible band. The jump to `O(n^2)` is a factor of `n / log n`, about `3x10^7`, which is the difference between finishing and never finishing. Spend the design argument on the class change, then optimise constants with measurements.
  • How much larger an input can a quadratic step absorb if the hardware gets 100x faster?
    About 10x, since feasible `n` scales as the square root of the speedup. That is the practical reason capacity planning cannot be substituted for an algorithm change: to absorb a 100x growth in event volume you would need a machine 10,000 times faster. The same 100x speedup would buy an `O(n log n)` step nearly a 100x larger input.

A constant-factor speedup is a head start; a better growth class is a faster runner. Over a long enough race the head start stops mattering.

saying these in an interview costs you the question

  • Big-O differences are just constant factors
  • A faster machine makes quadratic work fine at scale
  • n log n and n^2 are close for large inputs
  • Parallelism turns quadratic work into linear work
  • Growth classes only matter in academic exercises

context

open as a page

Why can't O(E+S) over E events and S servers be simplified to O(E)?

level: middleimportance: should knowfreq 52%

basics

~20 s

E and S are independent inputs, so neither provably dominates the other. Lower-order terms may only be dropped within a single variable. O(E+S) becomes O(E) only when the problem guarantees S is bounded by a multiple of E.

open as a page

A downsampling pass costs 5n log n + 200n steps — is O(n log n) an honest label?

level: seniorimportance: should knowfreq 44%

basics

~20 s

Formally yes: for large enough n the 5n log n term dominates. But 200n is the larger term for every n below roughly 10^12, so the label predicts the growth shape, not the runtime anyone will measure.

open as a page

Would you replace an O(n^2) step with an O(n log n) one when a contract caps input at 5,000 records?

level: principalimportance: should knowfreq 36%

basics

~20 s

Probably not on performance grounds alone: at 5,000 records the quadratic step is about 2.5x10^7 element operations, typically tens of milliseconds. Decide on exposure instead — how firm the cap is, what happens when it breaks, and who maintains the harder code.

open as a page