Build the cost model first
Before any specific algorithm, you need an automatic sense of what each structure costs for each operation. Not memorised as a table — internalised, so that "I need fast lookup by key and I don't care about order" produces "hash map" without deliberation.
- Make the table yourself, from memory, weekly: array, dynamic array, linked list, hash map, balanced tree, heap, stack, queue, graph representations. Insert, delete, lookup, ordered traversal.
- Know why, not just what. A hash map's O(1) lookup and a tree's O(log n) come from different mechanisms, and knowing which explains when each degrades.
- Know the degradations. Hash maps degrade with bad hashing, dynamic arrays have amortised costs with occasional expensive operations, and questions target exactly these.
- Attach a use case to each. A structure without a situation is a name.
The patterns are the syllabus
| Pattern | The signal that suggests it |
|---|---|
| Two pointers | Sorted array, pairs, or in-place partitioning |
| Sliding window | Contiguous subarray or substring with a constraint |
| Hash map for seen-before | Duplicates, complements, frequency counts |
| Binary search | Sorted input, or a monotonic answer space |
| BFS | Shortest path in an unweighted graph, level-by-level |
| DFS / backtracking | All paths, all combinations, constraint satisfaction |
| Dynamic programming | Overlapping subproblems and optimal substructure |
| Heap | Top-k, running median, merging sorted streams |
| Union-find | Connectivity and grouping over time |
| Topological sort | Ordering with dependencies |
Roughly a dozen patterns cover the large majority of problems in most courses and interview sets. Study the mapping from signal to pattern rather than the problems themselves — that's the selection skill that decides whether you can start an unfamiliar question.
How to work a problem so you learn from it
- 1
Spend five minutes on the brute force before anything clever
State it, state its complexity. This anchors what you're improving on and is often the fallback that earns partial credit in an exam or a working baseline in an interview.
- 2
Say which pattern the constraints suggest, out loud, before coding
"Contiguous subarray with a sum condition — sliding window." If you can't name a pattern, you're about to improvise, and improvised solutions don't transfer.
- 3
Set a hard time limit — thirty to forty minutes
Beyond that you're not learning, you're grinding. Look at the solution, understand the key insight, close it, and re-solve from scratch.
- 4
After solving, write one line: the insight
"Sorting first makes the two-pointer valid." This line is the transferable part and it's what you'll review. The code is not.
- 5
Re-solve it cold in a week, from the problem statement
If you can't, you memorised. Spaced re-solving is what distinguishes a hundred problems attempted from a hundred problems learned.
- 6
Group it with problems sharing the pattern, not the topic
Your notes should be organised by pattern. That's the retrieval structure you'll actually use.
Implement the structures once, from scratch
Using a library's hash map teaches you the interface. Writing one — with collision handling and resizing — teaches you why lookups can degrade, why load factor matters, and what an amortised cost actually means. That understanding is what exam questions about hashing are asking for.
Do this once per structure, not repeatedly. It's a comprehension exercise rather than a skill to drill, and the return drops sharply after the first implementation. A linked list, a hash map, a binary search tree with rotations, a heap and a graph traversal is a weekend and it changes how the rest of the course reads.
Exams and interviews want different things
| University exam | Technical interview | |
|---|---|---|
| Emphasis | Proofs, complexity analysis, correctness arguments | Working code under time pressure, communication |
| Format | Pseudocode or prose, by hand | Live coding, spoken reasoning |
| What's marked | Method, analysis, edge cases stated | Whether it runs, and whether you explained the approach |
| Preparation | Derive complexities, prove correctness, past papers | Volume of problems, spoken practice, mock interviews |
The overlap is large but the tails differ, and preparing for one while sitting the other is a common and costly mistake. Check your past papers: if they ask you to prove a greedy choice is optimal, no amount of problem-grinding prepares you for that.
Complexity analysis is a separate skill
- Practise analysing code you didn't write. Given a snippet, state the time and space complexity. Ten of these takes ten minutes and it's a common exam question in its own right.
- Learn to solve recurrences, at least well enough for the standard cases. Divide-and-conquer analysis depends on it.
- Distinguish worst, average and amortised precisely. Questions target the distinction, and "O(1) insert" for a dynamic array is only true amortised.
- Include space, which students routinely forget. Recursion's stack usage is the classic omission.
A realistic weekly routine
Three to five problems a week, worked properly with the insight line and the cold re-solve, beats twenty rushed ones. Add ten minutes of cost-model and pattern review, and one session a fortnight analysing complexity of unfamiliar code.
If you're preparing for interviews alongside coursework, keep them in separate sessions — the modes are different enough that mixing them tends to mean doing neither well. How to study computer science covers the wider course, and how to learn to code the implementation fluency that all of this rests on.