Measuring speed: Big-O notation
Describe how an algorithm’s work grows with the input size, learn the common growth rates, and the rules for simplifying Big-O.
O(n) means “the work grows in proportion to n”: twice the data, about twice the work. O(n²) means twice the data, four times the work.
The common growth rates
| Big-O | Name | Typical example | n doubles → work |
|---|---|---|---|
O(1) | array[i], Dictionary lookup | ||
O(log n) | |||
O(n) | |||
O(n log n) | Array.Sort | ||
O(n²) | |||
O(n³) | |||
O(2ⁿ) | |||
O(n!) |
Rule 1: drop the constants
3n + 5 steps is O(n). One that loops twice over the data (2n) is still O(n). Constants depend on the machine and compiler; the shape does not.
// 2n steps → O(n)int min = int.MaxValue, max = int.MinValue;foreach (int x in data) if (x < min) min = x;foreach (int x in data) if (x > max) max = x; // n/2 steps → still O(n)for (int i = 0; i < data.Length / 2; i++) (data[i], data[^(i + 1)]) = (data[^(i + 1)], data[i]);Rule 2: keep only the biggest term
n² + n + 100 steps, the n² part dominates as n grows (for n = 10,000 it is 100,000,000 against 10,100). So it is O(n²).
// Part 1: O(n)foreach (var beam in beams) Validate(beam); // Part 2: O(n²): every pairfor (int i = 0; i < beams.Length; i++) for (int j = i + 1; j < beams.Length; j++) CheckClash(beams[i], beams[j]); // Total: O(n + n²) = O(n²)Rule 3: different inputs get different letters
a and then over b is O(a + b). Looping over b inside a loop over a is O(a × b).
// O(a + b)foreach (var c in columns) Draw(c);foreach (var b in beams) Draw(b); // O(a × b)foreach (var c in columns) foreach (var b in beams) if (Touches(c, b)) Connect(c, b);Best, average and worst case
| Case | Linear search | Used for |
|---|---|---|
O(1): it is the first element | ||
O(n): about n/2 checks | ||
O(n): last element or not found |
Big-O, Big-Ω and Big-Θ
Big-O (O): an upper bound. “It grows no faster than this.” Big-Omega (Ω): a lower bound. “It grows at least this fast.” Any comparison sort is Ω(n log n). Big-Theta (Θ): both at once. “It grows exactly like this.” Merge sort is Θ(n log n).
a.Length).
Show a hint
Show the solution
int First(int[] a) => a[0]; // O(1) int Sum(int[] a) // O(n){ int s = 0; foreach (int x in a) s += x; return s;} bool HasPairWithSum(int[] a, int target) // O(n²){ for (int i = 0; i < a.Length; i++) for (int j = i + 1; j < a.Length; j++) if (a[i] + a[j] == target) return true; return false;} int SumFirstTen(int[] a) // O(1): at most 10 steps{ int s = 0; for (int i = 0; i < Math.Min(10, a.Length); i++) s += a[i]; return s;}Remember
Big-O describes how the work grows with the input size n, not the exact time. Common rates from fast to slow: O(1), O(log n), O(n), O(n log n), O(n²), O(2ⁿ), O(n!). Drop constants, keep the biggest term, and use different letters for different inputs. Unless stated otherwise, Big-O means the worst case.