Complexity Analysis: Practice Questions
100 questions. Try each one yourself before checking the answer.
Short on time? Filter by Must Do for the 25 questions that cover this topic on their own.
Before any notation: count how many times the work actually happens.
Count the operations in three different loop shapes.
How each growth class actually feels at n = 10, 1,000 and 1,000,000.
Why 2n and n are both called O(n).
Why n^2 + n + 100 is just O(n^2).
The actual definition of big-O, with a concrete witness.
Three notations, three different claims.
What constant time means — and what it does not.
Halving, and how few steps it really takes.
Linear time, and how to recognise it.
The sorting class, measured.
Quadratic time, and the moment it becomes unusable.
Exponential growth, without recursion.
Factorial time, and why brute-forcing orderings fails immediately.
Put all the classes on one chart and find the crossovers.
The same algorithm has three different complexities.
Best case is not "small n", and worst case is a promise.
Memory has a complexity too.
In-place versus allocating, and why it matters.
The complexity of every common list operation, measured.
Dictionary and set operations, measured against lists.
Strings are immutable, and that changes every cost.
How to time code so the number means something.
How to measure memory, and why getsizeof lies.
A checklist for reading the complexity off unfamiliar code.
Sequential loops add; nested loops multiply. Apply the rule to eight functions.
Loops whose counter multiplies, divides, or skips.
Inner loops whose bound depends on the outer variable.
When there are two inputs, n is not enough.
The lines that look like one operation and are really a loop.
.count() and .index() inside a comprehension.
Slices copy, and copies inside loops are quadratic.
Building output: four approaches, two complexities.
The two ends of a list have different costs, and it decides your data structure.
Converting between structures is never free.
sorted() inside a loop is the most expensive innocent line in Python.
min, max, sum, any, all — all O(n), and when that compounds.
Nested comprehensions, and reading their cost.
any, all, and, or stop early — unless you stop them.
An early return improves the best case and never the worst.
Working out the cost when functions call other functions.
Why list.append is O(1) when it sometimes copies everything.
Watch the resize happen, and what pre-sizing saves.
Three different kinds of "it is usually fast".
Spending memory to buy speed, measured both ways.
Generators: the same time, a fraction of the memory.
Why len() is O(1), and what that tells you about the design.
Membership testing: the measurement that fixes the most code.
One problem, five correct solutions, a hundredfold apart.
The complexity of every Python operation you will use in this track.
The required complexity tells you which approach to use before you write any code.
Four ways to find duplicates, and how the constraint picks one.
Finding what two collections have in common.
Counting: five approaches, and where each belongs.
Finding the largest k, and why sorting is usually the wrong tool.
Sorting versus counting, and when each wins.
Turning a repeated search into a single index build.
Grids: why O(n^2) is usually the wrong way to say it.
When the cost depends on the size of the ANSWER, not the input.
O(n^2) is often the right answer.
Find the crossover where the better complexity actually wins.
Pay once, query many times.
Measure both axes and choose deliberately.
Caching changes the complexity of a workload, not of a function.
Work out the complexity of a function you did not write.
Predict the runtime before you write the code.
The numbers worth memorising.
Sometimes the algorithm is not the bottleneck at all.
Let the profiler tell you where the time goes.
The most valuable optimisation decision is often "no".
Six functions with one visible loop each. Three are quadratic.
Growing a result: the three ways it goes quadratic.
Consuming a collection from the wrong end.
Recomputing an aggregate that could be maintained.
Four "optimisations" that made things slower.
Code that could stop early and does not.
Nested loops that are not quadratic, and flat loops that are.
When O(1) average becomes O(n), on purpose.
Code whose time complexity is fine and whose memory is not.
Amortised O(1) can still stall.
Two O(n) functions that differ by 50x.
Ten functions, no labels. State the complexity of each.
Five benchmarks that report the wrong answer.
A slow function, diagnosed end to end.
Review a module the way you would review a colleague's pull request.
Build the measuring tool you will use for the rest of this track.
Plot growth curves in the terminal.
Count operations instead of timing them.
Measure what data structures actually cost.
Build a self-testing quiz that generates functions and checks your answer.
Find the input size where one implementation overtakes another, then build a hybrid.
Catch a performance regression before it ships.
Predict a program's runtime from a model, then check the prediction.
Generate a complexity report card for a module.
Infer a complexity from a black box you cannot read.
Explain big-O to three different audiences.
"The dashboard got slow." Work the problem.
Design a data structure to meet stated complexity bounds.
A complexity-focused interview, transcribed.
Take a slow, working module and make it fast, provably.
Stuck? Solve it with a mentor.
Your first 1-on-1 session is free.