Fifteen Problem Shapes and the Move That Solves Each
Fifteen LeetCode patterns written as signal plus move: hash maps, two pointers, sliding window, prefix sums, heaps, backtracking, dynamic programming, BFS, DFS and Dijkstra, with a recognition table and a way to practise so they stick.
Aug 13, 202615 min read

LeetCode patterns are shapes, not answers to memorise
If you have been grinding problems and still freeze on a new one, the fix is to stop thinking in problems and start thinking in LeetCode patterns: a small set of problem shapes, each with a move that usually works. Most of the difficulty in a new problem is not the code. It is noticing which shape you are holding.
The usual way to learn algorithms is to work through a long list and hope something generalises. Sometimes it does. More often people finish with a hundred solutions memorised, meet the hundred and first, and discover they learned answers rather than the thing that produces answers. An experienced engineer looking at a new problem is not recalling a solution. They are noticing that the input is sorted, or that the same subproblem keeps reappearing, and reaching for the matching move.
Below are fifteen of those pairings, in roughly the order they come up in real code rather than the order that sounds impressive. Each one is written as a signal + a condition → the move, because that is how recognition actually works in your head.
How to recognise coding interview patterns quickly
Before the list, a word on how to use it. Whether you meet these in a coding round or in a slow page at work, the question you ask is the same: what does the input look like, and what exactly am I being asked for? Read the problem once for those two things before you think about code.
A few words in a problem statement do a lot of the work for you:
| If the problem says... | Suspect this pattern first |
|---|---|
| "sorted array", "find a pair", "in place" | Two pointers or binary search |
| "contiguous subarray", "longest substring" | Sliding window |
| "sum of a range", asked many times | Prefix sums |
| "top k", "k largest", "k closest" | A heap of size k |
| "all combinations", "all permutations" | Backtracking with pruning |
| "minimum cost", "number of ways", "can you reach" | Dynamic programming |
| "fewest steps", grid or unweighted graph | Breadth first search |
| "depends on", "order of tasks", "cycle" | Depth first search, topological sort |
This is a starting guess, not a verdict. Plenty of problems wear the costume of one pattern and turn out to need another. But a guess you can test beats a blank page. If you are right at the start of this, my post on how to learn DSA from scratch gives you the order to meet these in, and the question on how to start DSA when you cannot solve problems covers the first few weeks.
Removing a loop you did not need
These four account for a surprising share of real speedups. None of them is glamorous.
1. Repeated lookups + a list → a hash map
The most valuable algorithmic move there is, and the least exciting. A scan inside a loop is quadratic; a lookup inside a loop is linear. A large share of accidentally slow code is exactly this and nothing more. Two Sum is the classroom version. The production version is a function that checks "is this user in the list of blocked users" for every row of a report.
The tell: you see for inside for, and the inner loop is only searching for a match.
2. Many questions about order + one dataset → sort once, up front
Sorting costs you one logarithmic factor and then makes duplicates adjacent, extremes reachable and binary search possible. If you are going to ask many questions of the same data, pay once. Merging overlapping intervals, finding duplicates and grouping anagrams all get easier the moment the data is in order.
The tell: you keep writing code that would be trivial "if only these were in order".
3. Sorted data + a search → binary search
Halving the search space at each step is the difference between a million comparisons and about twenty. It is also the algorithm people most often get subtly wrong from memory. Joshua Bloch wrote in 2006 that the binary search in the Java library carried an overflow bug for about nine years, because (low + high) / 2 overflows on very large arrays. Write it carefully once, use low + (high - low) / 2, and remember that the tricky part is always the boundary condition.
The bigger idea is that binary search works on any answer space that is monotonic, not only on arrays. "What is the smallest capacity that ships everything in D days" is a binary search over capacities.
4. Sorted data + finding a pair → two pointers
One pointer at each end, moving inward depending on whether the current sum is too big or too small. It turns an obvious quadratic search into a single pass. Its same-direction cousin (a slow and a fast pointer) handles removing duplicates in place and detecting a cycle in a linked list.
The tell: sorted input, and the answer is about a relationship between two elements.
The sliding window technique and other sequence patterns
5. A contiguous run + a constraint → a sliding window
Longest substring without repeating characters, maximum sum of a subarray of length k, smallest window containing every required character. Grow the window on the right, shrink it from the left when the constraint breaks, and never look at the same element more than twice.
The difference from two pointers is worth being precise about: a sliding window cares about everything inside the range, while two pointers usually cares only about the two endpoints. If the word "contiguous" or "substring" appears, try the window first.
6. Many range sums + data that does not change → prefix sums
Precompute the running total once and any range sum becomes a single subtraction. It is the cheapest example of a general principle: repeated queries justify preprocessing. Combine it with a hash map and you can count "subarrays that sum to k" in one pass, which is one of the most reused tricks in the whole list.
7. The top k items + a large stream → a heap of size k
Do not sort a million things to find the ten biggest. Keep k of them in a min heap and evict the smallest when something bigger arrives. That turns the memory you need from the size of the data into the size of the answer. Python's own documentation says heapq.nlargest performs best for smaller values of n, and that for large n a plain sorted() wins, which is exactly the trade-off in one sentence.
When the answer is a search through possibilities
8. A big problem + smaller copies of itself → divide and conquer
Split, solve each part, combine. Merge sort and quicksort are the famous cases, but the pattern matters more than either: building a balanced tree from a sorted array, counting inversions and many tree problems are all "solve the left, solve the right, combine".
9. Every combination + constraints that rule most out → backtracking with pruning
Build the answer one choice at a time, and abandon a branch the moment it cannot work. Subsets, permutations, N-Queens, Sudoku. The pruning is not an optimisation detail. It is usually the entire difference between a program that finishes and one that does not.
The tell: the problem asks for all valid arrangements, or the input is small (often under 20) because the intended solution is exponential.
10. Overlapping subproblems + a best answer → dynamic programming
If your recursion computes the same thing again and again, cache it. That is most of what dynamic programming is. Write the honest recursive solution first, add memoisation, and only convert it to a table if you need the memory or the speed. Almost nobody arrives at the table directly, whatever the textbooks imply.
The tell: "minimum cost", "maximum profit", "number of ways", and a choice at each step that affects what is possible later. The Grokking Dynamic Programming Patterns for Coding Interviews course groups these into families, which is the right way to study them.
11. A locally obvious choice + a reason it stays correct → greedy
Greedy algorithms are short, fast and wrong more often than people expect. The rule is not "take the best local option". It is "take the best local option, then convince yourself with an actual argument that it cannot paint you into a corner". Interval scheduling by earliest finish time is greedy and correct. Making change with arbitrary coin values is greedy and wrong. If you cannot explain why, reach for dynamic programming instead.
BFS vs DFS and graph patterns
Many problems that look new are graph problems in disguise: a grid is a graph, a set of course prerequisites is a graph, a word ladder is a graph.
12. The fewest steps + edges that all cost the same → breadth first search
Layer by layer with a queue. The first time you reach the target is the shortest path, and that guarantee disappears the moment edges have different weights. Shortest path in a maze, minimum moves in a puzzle, spreading infection across a grid: all BFS.
13. Reachability, cycles or ordering → depth first search
Can I get there, does this depend on itself, in what order can these run? Counting islands, detecting cycles and topological sorting all fall out of DFS. Topological sort is what every build system and task scheduler is doing underneath, which is a nice reminder that this is not only an exam topic.
14. Shortest path + weighted edges → Dijkstra
Breadth first search with a priority queue instead of a plain queue, which is a genuinely useful way to remember it. Know also where it stops being correct: Dijkstra's algorithm does not handle negative edge weights, which is why Bellman-Ford exists. Knowing where an algorithm breaks is more useful than knowing how it works. For more practice on this family, Grokking Graph Algorithms for Coding Interviews and the VisuAlgo animations are both worth your time.
15. A clever algorithm + no measurement → use the simple one
The last pattern is the one that stops you misusing the other fourteen. A quadratic loop over twelve items is fine forever. The sophisticated version costs reader comprehension every time someone opens the file, and that cost is real and recurring while the speed gain may be imaginary. Donald Knuth put it well in 1974: programmers should forget about small efficiencies about 97% of the time, without passing up the critical 3%. Measure, then decide.
All fifteen LeetCode patterns in one table
| # | Signal | Move | Typical cost after |
|---|---|---|---|
| 1 | Repeated lookups in a list | Hash map | O(n) |
| 2 | Many order questions | Sort once | O(n log n) once |
| 3 | Sorted data, search | Binary search | O(log n) |
| 4 | Sorted data, pair | Two pointers | O(n) |
| 5 | Contiguous run, constraint | Sliding window | O(n) |
| 6 | Many range sums | Prefix sums | O(1) per query |
| 7 | Top k of many | Heap of size k | O(n log k) |
| 8 | Problem splits into copies | Divide and conquer | Often O(n log n) |
| 9 | All combinations | Backtracking + pruning | Exponential, pruned |
| 10 | Overlapping subproblems | Dynamic programming | States × transitions |
| 11 | Provably safe local choice | Greedy | Often O(n log n) |
| 12 | Fewest steps, equal weights | BFS | O(V + E) |
| 13 | Reachability, order, cycles | DFS | O(V + E) |
| 14 | Weighted shortest path | Dijkstra | O(E log V) |
| 15 | No measured problem | Simple code | Whatever is clearest |
The DSA cheat sheet has the same patterns with templates, and there are language versions for C++, Java and JavaScript. The free Big-O Cheat Sheet is handy for the complexity column.
How to practise DSA patterns so they stick
Knowing the list is not the same as recognising a pattern cold. Here is what I suggest to students who ask me how to turn this into a reflex:
- Study one pattern at a time. Solve five or six problems of the same shape back to back so your brain notices the repetition. The free LeetCode Patterns by Sean Prashad list is grouped this way, and Grokking the Coding Interview: Patterns for Coding Questions teaches by pattern too.
- Write the brute force first. A correct slow solution gives you something to test the fast one against, often reveals the structure you needed, and is sometimes fast enough that you never write the second one.
- Then mix them up. Once a few patterns feel familiar, do sessions where you do not know the pattern in advance. That trains recognition, which is the actual skill.
- Say the signal out loud. Before coding, say "sorted plus pair, so two pointers" or "overlapping subproblems, so memoise". If you cannot name the signal, you are guessing.
- Keep a log of misses. When you picked the wrong pattern, write down what fooled you. That list becomes your most valuable revision sheet.
How many problems is enough? Fewer than LinkedIn suggests. I answered this properly in how many LeetCode problems are enough, and if contest-style problems make you miserable, you are allowed to skip competitive programming.
What else belongs on this list
A few near misses worth knowing once the fifteen feel natural:
- Monotonic stack. "Next greater element" and "largest rectangle in a histogram" are stack problems in disguise.
- Union find. Grouping things that keep turning out to be connected. Small enough to write from memory.
- Tries. When the question is "what starts with this" rather than "what equals this".
- Bit manipulation. Narrow, but unreasonably effective where it applies.
- Hashing itself, one level down. Knowing why a hash map degrades tells you when it will. My post on choosing a data structure is choosing what to make cheap goes further on that.
And the meta rule that outranks all of them: get a correct brute force working first, always.
My honest read
Fifteen shapes, and recognising which one you are looking at is the skill. The implementations are the easy half, and they are also the half you can look up. If you practise by pattern, name the signal before you code, and keep a log of the times you guessed wrong, you will find that new problems start to look like old friends in slightly different clothes. That is what "being good at DSA" actually feels like from the inside.
Balance it with building things, though. Patterns get you through one round of a hiring process, not the whole job. The DSA roadmap sits alongside the wider job-ready roadmap for exactly that reason.
Learn it on Sefism
- DSA roadmap and the DSA cheat sheet
- How to learn DSA from scratch, a 12-week plan
- Grokking the Coding Interview: Patterns for Coding Questions for structured pattern practice
- LeetCode Patterns by Sean Prashad, a free grouped problem list
- VisuAlgo to watch the algorithms run
- Career questions library for the questions students ask me most
FAQ
What are the most important LeetCode patterns?
Hash maps, two pointers, sliding window, binary search, prefix sums, heaps for top k, BFS and DFS, backtracking and dynamic programming cover most problems you will meet. Learn them in roughly that order, one at a time.
How do I know which pattern to use for a problem?
Look at the input and the question before anything else. Sorted input suggests binary search or two pointers, "contiguous" suggests a sliding window, "fewest steps" suggests BFS, and "number of ways" or "minimum cost" suggests dynamic programming.
What is the difference between sliding window and two pointers?
A sliding window tracks everything inside a contiguous range and grows or shrinks it. Two pointers usually compares the two elements at the pointer positions, often on sorted data. Windows are for substrings and subarrays; two pointers is for pairs and in-place edits.
When should I use BFS instead of DFS?
Use BFS when you need the fewest steps in a graph where every edge costs the same. Use DFS for reachability, cycle detection, counting connected regions and topological ordering.
Is memorising LeetCode solutions a good strategy?
No. Memorised solutions do not transfer to new problems. Learn the pattern, re-solve problems from a blank file after a few days, and keep a log of which signals you missed.
Ask your own question
If your situation is different from anything here, the career questions library has honest answers to the questions students and engineers ask me most.
Want a learning roadmap built around you, written answers to your own questions and a place to discuss your FYP? Create your free Sefism account. Members can also book a one to one session when they want to talk it through.
Stay in touch
- LinkedIn: where I share roadmaps, career advice and honest takes on hiring. Follow, or message me.
- X (Twitter): short practical thoughts on engineering and careers.
- Instagram: quick tips and a more personal side.
- Sefism Discord: meet other students and engineers working through the same job market and share what is working.
- Sefism on YouTube: walkthroughs and talks.
Comments (0)
Comments are closed for now.
No comments yet.