Coding Interview Patterns: How to Recognize and Solve Them
By Kieron
Last updated October 4, 2026

Coding interviews reward pattern recognition and clear communication more than raw cleverness. Almost every problem you will see is a variation on a dozen patterns, and interviewers watch how you get from a vague prompt to working code as closely as they watch the code itself. This guide lists the patterns, the signals in a problem that point to each one, a study plan, and how to run the 45 minutes.
It replaces our separate short pages on arrays, hash tables, linked lists, trees, graphs, recursion, sorting, binary search and dynamic programming, because those topics are easier to learn together than apart.
How a coding interview is scored
Interviewers typically write notes on four things: whether you understood the problem, whether your approach was sound, whether your code worked and was clean, and how you communicated. Getting the optimal solution helps, but a candidate who clarifies the problem, proposes a reasonable approach, codes it cleanly and tests it often scores better than one who silently produces the optimal answer. Practice the whole loop, not only the algorithm.
Match the signal to the pattern
| If the problem says... | Try this | Typical cost |
|---|---|---|
| "find a pair / has duplicate / count occurrences" | Hash map or set | O(n) time, O(n) space |
| Sorted array, or a pair/triple that meets a condition | Two pointers | O(n) after sorting |
| Longest/shortest/max-sum contiguous subarray or substring | Sliding window | O(n) |
| Sorted input, or "minimum value that works" | Binary search (on index or on the answer) | O(log n) |
| Shortest path in an unweighted graph or grid, level by level | BFS | O(V + E) |
| Explore all connected cells, paths, or components | DFS | O(V + E) |
| Tree questions (depth, path sum, validate BST) | Recursion with a clear return value | O(n), O(h) stack |
| "All combinations / permutations / subsets" | Backtracking | Exponential; prune early |
| "Number of ways" or "min/max cost" with overlapping subproblems | Dynamic programming | Usually O(n) to O(n*m) |
| "Top k", "kth largest", merge sorted streams | Heap | O(n log k) |
| "Next greater element", matching brackets | Stack (monotonic stack) | O(n) |
| Overlapping ranges, meeting rooms | Sort by start, sweep | O(n log n) |
| Linked list cycle, middle node, reverse | Fast/slow pointers; pointer reversal | O(n), O(1) space |
The patterns, with one example each
Hash map: remember what you have seen
The brute-force answer to "find two numbers that sum to a target" checks every pair, O(n²). A hash map lets you ask "have I already seen the number I need?" in constant time:
def two_sum(nums, target):
seen = {} # value -> index
for i, n in enumerate(nums):
if target - n in seen:
return [seen[target - n], i]
seen[n] = i
return []
Sliding window: contiguous ranges without recomputing
Longest substring without repeating characters. Grow the right edge; when a repeat appears, shrink the left edge until the window is valid again:
def longest_unique(s):
last, left, best = {}, 0, 0
for right, ch in enumerate(s):
if ch in last and last[ch] >= left:
left = last[ch] + 1
last[ch] = right
best = max(best, right - left + 1)
return best
Binary search, including "search on the answer"
Beyond finding a value in a sorted array, binary search works whenever you can test a candidate answer and the result flips from false to true at some point. For example, "the minimum speed that finishes in time" tests a speed and moves left or right:
def first_true(lo, hi, ok):
# smallest x in [lo, hi] where ok(x) is True, assuming ok is monotonic
while lo < hi:
mid = (lo + hi) // 2
if ok(mid):
hi = mid
else:
lo = mid + 1
return lo
BFS and DFS: graphs and grids
Treat a grid as a graph. BFS finds the shortest path when every step costs the same; DFS is the natural fit for counting islands or checking connectivity. Mark nodes visited when you add them to the queue, not when you pop them, or you will enqueue duplicates:
from collections import deque
def shortest_path(grid, start, end):
rows, cols = len(grid), len(grid[0])
q, seen = deque([(start, 0)]), {start}
while q:
(r, c), dist = q.popleft()
if (r, c) == end:
return dist
for dr, dc in ((1,0),(-1,0),(0,1),(0,-1)):
nr, nc = r + dr, c + dc
if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] == 0 and (nr, nc) not in seen:
seen.add((nr, nc))
q.append(((nr, nc), dist + 1))
return -1
Trees: decide what each call returns
Most tree bugs come from not deciding what the recursive function returns. For maximum depth the answer is one line once you decide it returns "the depth of this subtree":
def max_depth(node):
if not node:
return 0
return 1 + max(max_depth(node.left), max_depth(node.right))
Backtracking: choose, explore, undo
def subsets(nums):
out, path = [], []
def go(i):
if i == len(nums):
out.append(path[:])
return
go(i + 1) # skip nums[i]
path.append(nums[i]) # take nums[i]
go(i + 1)
path.pop() # undo
go(0)
return out
Dynamic programming: name the state first
Do not start by writing a table. Say out loud: "the state is the best answer using the first i items", then "the choice at each step is X or Y", then write the recurrence. Climbing stairs (n steps, one or two at a time) is the smallest example:
def climb(n):
a, b = 1, 1 # ways to reach step 0 and 1
for _ in range(n - 1):
a, b = b, a + b
return b
Start with a plain recursive solution, add memoization if subproblems repeat, and only then convert to a table if you need the speed.
Linked lists: two pointers and reversal
Draw the pointers on paper before coding. Reversing a list in place is the foundation for a surprising number of questions:
def reverse(head):
prev = None
while head:
head.next, prev, head = prev, head, head.next
return prev
Data structures you should be able to explain, not just use
- Array / dynamic array: O(1) index, amortized O(1) append, O(n) insert in the middle.
- Hash table: average O(1) lookup and insert, O(n) worst case with many collisions; keys must be hashable and order is not the point.
- Heap: O(log n) push and pop, O(1) peek at the min or max.
- Balanced BST / sorted structure: O(log n) ordered operations, useful when you need floor/ceiling or ranges.
- Graph: adjacency list for sparse graphs, matrix for dense ones.
Interviewers love to ask "what is the trade-off?" Having this table in your head is the answer.
Running the 45 minutes
- Minutes 0-5: clarify. Restate the problem in your own words. Ask about input size, duplicates, empty input, negative numbers, and whether the input is sorted.
- Minutes 5-12: approach. Say the brute force and its cost, then the better idea and why. Get the interviewer to agree before you code.
- Minutes 12-35: code. Narrate as you type. Use clear variable names. If you get stuck, say what you are trying and what is not working.
- Minutes 35-42: test. Walk through one normal example and one edge case by hand. Catch your own bugs before the interviewer does.
- Minutes 42-45: wrap up. State time and space complexity, and mention one improvement you would make with more time.
A study plan that is not 400 problems
| Week | Focus | Goal |
|---|---|---|
| 1 | Arrays, strings, hash maps, two pointers | Solve easy-to-medium problems without hints |
| 2 | Sliding window, binary search, stacks | Recognize the signal in under a minute |
| 3 | Trees, BFS/DFS, linked lists | Write recursion with a clear return value |
| 4 | Backtracking, DP, heaps | Name the state and recurrence before coding |
| 5+ | Timed mixed sets, mock interviews out loud | Finish a medium in about 25 minutes and explain it |
For each problem, after you solve it (or give up after 20-30 minutes), write down the pattern and the signal that revealed it. Reviewing the pattern list weekly beats grinding new problems. A mock interview where you have to talk through your solution out loud closes the gap between solving and explaining.
Common mistakes
- Coding before agreeing on the approach. You lose ten minutes on the wrong idea.
- Going silent when stuck. Interviewers can only credit and help with what they hear.
- Skipping edge cases like empty input, a single element, and duplicates.
- Memorizing solutions. A small change to the problem breaks a memorized answer; a pattern survives it.
- Optimizing too early. A correct O(n²) answer you can improve is better than a broken O(n) attempt.
Frequently asked questions
How many LeetCode problems should I solve before interviews?
There is no magic number. A few dozen well-reviewed problems covering each pattern above, plus timed practice, does more than hundreds solved without reflection.
What is the best language for coding interviews?
The one you know best, unless the job requires a specific language. Python is popular because it is concise, but you should know your language's standard library for heaps, queues and hash maps.
What if I cannot solve the problem?
Say so, describe the brute force, and ask for a hint. A working suboptimal solution plus clear thinking usually scores better than an incomplete optimal attempt.
Can I use AI during a coding interview?
Only if the employer says it is allowed. Some do now, and many proctored assessments forbid it. Read our guide to the rules and how to use AI for coding practice.
Put this into practice
Continue with the Aissence workflow this guide supports.