skip to content

questions

4

What does the statement 'this algorithm is O(n)' formally claim, and why are constants and lower-order terms dropped?

level: juniorimportance: must knowfreq 88%

answer

  1. growth rate, not a step count
  2. there is a hidden constant factor
  3. the bound only holds past a threshold
  4. f(n) at most c times g(n), eventually
  5. the dominant term swallows the rest

basics

~20 s

Saying an algorithm is O(n) claims its running time is bounded above by a constant times n for all sufficiently large inputs. Constants and lower-order terms are dropped because the notation describes growth rate, not exact operation counts.

solid answer

~40 s

Formally, `f(n) = O(g(n))` means there exist a constant `c > 0` and a threshold `n0` such that `f(n) <= c * g(n)` for every `n >= n0`. Two consequences follow. Constant factors vanish because they are absorbed into `c` — `5n` and `500n` are both O(n), which is what makes the notation machine-independent. Lower-order terms vanish because the dominant term eventually dwarfs them: `3n^2 + 50n` is O(n^2) since past some point the quadratic term dominates. The price of the abstraction is that Big-O says nothing about small inputs or real constants — an O(n) algorithm with a huge constant can lose to an O(n^2) one at practical sizes. And it is only an upper bound: an O(n) algorithm is, technically, also O(n^2).

go deeper

for a junior

Be ready to state what O(n) means in plain words — bounded above by a constant times n for large inputs — and to simplify an expression like 3n^2 + 50n + 7 to O(n^2) without hesitation.

for a middle

An interviewer expects the formal definition with c and n0, a clean explanation of why constants and lower-order terms drop, and awareness that Big-O is an upper bound while Theta is the tight claim.

for a senior

Demonstrate judgment about what the notation hides: constants that decide real performance at practical sizes, and why an asymptotically worse choice can be the right engineering call for bounded inputs. Connect the abstraction to measurement.

for a principal

Own the framing question: when a team debates an optimization, steer them to whether n actually grows in production before anyone quotes asymptotics. Asymptotic arguments justify architecture; measured constants justify code changes.

## The formal definition Big-O is a statement about functions, not about code. We write `f(n) = O(g(n))` — read "f is Big-O of g" — when there exist a positive constant `c` and a threshold `n0` such that: ``` f(n) <= c * g(n) for all n >= n0 ``` In words: **beyond some input size, f is bounded above by a constant multiple of g.** Big-O names a *set* of functions (everything that grows no faster than g, up to a constant), and the claim "this algorithm is O(n)" says its running-time function belongs to that set. ## A worked example Suppose an algorithm performs exactly `3n^2 + 50n + 7` operations on an input of `n` records. Claim: this is O(n^2). Proof sketch: for `n >= 51`, we have `50n + 7 <= n^2`, so `3n^2 + 50n + 7 <= 4n^2`. Picking `c = 4` and `n0 = 51` satisfies the definition. Nobody memorizes these constants — the point is that *some* pair exists, which is all the definition asks. ## Why constants are dropped Two reasons, one practical and one formal: - **Step counting is ambiguous.** Is `a[i] + 1` one operation or three (index, load, add)? Different machines, compilers, and counting conventions give different constants for the *same* algorithm. Any convention-dependent factor is meaningless as a property of the algorithm itself. - **The definition absorbs them.** Whatever constant your counting produces disappears into `c`. That is deliberate: it makes the statement a property of the algorithm's *growth*, portable across hardware. ## Why lower-order terms are dropped Because the dominant term eventually dwarfs the rest. In `3n^2 + 50n + 7` at `n = 1,000,000`, the `3n^2` term contributes 3,000,000,000,000 operations while `50n` contributes 50,000,000 — under 0.002% of the total. Asymptotic notation is exactly the discipline of caring about behavior as `n` grows without bound, and in that regime only the fastest-growing term matters. ## What Big-O does not say This is where competent engineers go wrong, so state each direction carefully: - **It is not an operation count.** O(n) does not mean "performs n steps"; it means "performs at most a constant times n steps, eventually". The constant is hidden and can be enormous. - **It predicts nothing at small n.** The bound only takes effect past `n0`, and the hidden constant governs everything before growth dominates. An O(n) algorithm with a big constant genuinely loses to an O(n^2) algorithm on small inputs — which is precisely why mainstream production sort implementations switch to a simple quadratic sort on small runs. Asymptotic superiority is a statement about *sufficiently large* inputs only. - **O(1) does not mean fast.** It means the cost does not grow with `n`. A constant cost of ten million operations is still O(1). - **It is an upper bound, not a tight claim.** Since Big-O only bounds from above, every O(n) function is also O(n^2), O(n^3), and O(2^n) — all formally true, all uselessly loose. The notation family exists to say more when you need to: **Big-Omega** (`Ω`) makes the mirror-image *lower*-bound claim (`f(n) >= c * g(n)` eventually), and **Big-Theta** (`Θ`) makes the two-sided *tight* claim — bounded above and below by constant multiples of the same `g`. When someone says "linear time" and means it exactly, the honest notation is Θ(n). ## The family at a glance | Notation | Claim | Rough analogue | |---|---|---| | `O(g)` | grows no faster than g | `<=` | | `Ω(g)` | grows at least as fast as g | `>=` | | `Θ(g)` | grows exactly as fast as g | `=` | | `o(g)` | grows strictly slower than g | `<` | Everyday speech uses O loosely to mean Θ ("this loop is O(n)" usually intends "exactly linear"). That shorthand is harmless in conversation but the distinction carries real weight in specs, reviews, and proofs — an upper bound can never, by itself, establish that anything is slow.

  • Your O(n) routine has a large constant and a teammate's O(n^2) routine beats it on your real inputs of about 200 records — which claim is wrong?
    Neither. Big-O speaks only asymptotically: at a fixed small size, hidden constants decide, and an O(n^2) routine with tiny constants can legitimately win. The asymptotic claim says the O(n) routine must win *eventually*, for large enough n. For a bounded real workload, measure both and pick the faster one; keep the asymptotics in mind only if the input can grow.
  • Why does the definition include the threshold n0 instead of requiring the inequality for all n?
    Because small inputs are noise. Lower-order terms and constants can dominate at small n — 50n + 7 exceeds n^2 until n reaches 51 — and no finite prefix of sizes tells you anything about growth. Requiring the bound only eventually lets the notation ignore any finite amount of early misbehavior, which is exactly the abstraction it is designed to provide.
  • Does O(1) mean fast?
    No — it means the cost does not depend on n. The hidden constant can be huge: an O(1) operation costing a million steps loses to an O(log n) operation with a small constant at any realistic size. O(1) is a claim about scaling behavior, not about speed.

Big-O is like a speed limit: it caps how fast the running time can grow, without claiming the algorithm ever actually drives that fast.

saying these in an interview costs you the question

  • Says O(n) means the algorithm performs exactly n operations
  • Believes an O(n) algorithm beats an O(n^2) one at every input size
  • Thinks dropping constants means constant factors never matter in practice
  • Cannot explain why 3n^2 + 50n simplifies to O(n^2)

context

open as a page

Is calling a single non-nested catalog loop 'O(n^2)' wrong, technically true, or both — and what should a precise reviewer say instead?

level: middleimportance: must knowfreq 62%

basics

~20 s

Technically true, practically misleading. Big-O is only an upper bound, so a linear scan is O(n^2) in the same trivial sense it is O(n^3). The implied complaint — quadratic growth — is false: the tight bound is Theta(n).

open as a page

Why is it a misconception that Big-O notation means worst-case running time?

level: middleimportance: should knowfreq 50%

basics

~20 s

Big-O bounds the growth of a function; the case — best, worst, average — chooses which function you bound. They are independent axes: a worst case can have O, Theta, and Omega bounds, and a best case can meaningfully be Omega(n).

open as a page

What does a running-time guarantee of o(n log n) promise that O(n log n) does not, and what may a caller actually rely on?

level: seniorimportance: nice to knowfreq 15%

basics

~20 s

Little-o is strictly stronger: o(n log n) means the running time grows strictly slower than n log n — their ratio tends to zero — while O(n log n) permits growth exactly proportional to n log n. Neither promises anything about constants or small inputs.

open as a page