15 DSA Patterns That Solve Most Coding Interview Questions
The 15 data-structure and algorithm patterns behind most LeetCode and HackerRank interview problems — how to recognise each from the problem statement, a minimal Python template, typical complexity, and classic practice questions.
Grinding 500 random LeetCode problems is the slow way to get good at coding interviews. The fast way is noticing that most questions are the same 15 ideas wearing different costumes. Once you can say "this is a sliding window problem" in the first minute, the rest is execution.
For each pattern below: how to spot it, a minimal Python template, the usual complexity, and classic problems to practise. If you want the process for the interview itself, pair this with how to crack a DSA coding round.
1. Two pointers
Spot it: sorted array or string, pairs that sum to a target, removing duplicates in place, palindromes.
def pair_with_sum(nums, target): # nums is sorted
lo, hi = 0, len(nums) - 1
while lo < hi:
s = nums[lo] + nums[hi]
if s == target:
return lo, hi
if s < target:
lo += 1
else:
hi -= 1
return NoneComplexity: O(n) time, O(1) space. Practise: Two Sum II, 3Sum, Container With Most Water, Valid Palindrome.
2. Sliding window
Spot it: "longest / shortest / count of contiguous subarray or substring" with some condition.
def longest_unique_substring(s):
seen, left, best = {}, 0, 0
for right, ch in enumerate(s):
if ch in seen and seen[ch] >= left:
left = seen[ch] + 1
seen[ch] = right
best = max(best, right - left + 1)
return bestComplexity: O(n). Practise: Longest Substring Without Repeating Characters, Minimum Window Substring, Max Consecutive Ones III.
3. Fast and slow pointers
Spot it: linked lists or sequences with possible cycles, finding the middle.
def has_cycle(head):
slow = fast = head
while fast and fast.next:
slow, fast = slow.next, fast.next.next
if slow is fast:
return True
return FalseComplexity: O(n), O(1) space. Practise: Linked List Cycle II, Middle of the Linked List, Happy Number.
4. Binary search (including "on the answer")
Spot it: sorted input, or "find the minimum/maximum value such that a condition holds" where the condition is monotonic.
def min_capacity(weights, days): # search the answer space
def can_ship(cap):
need, load = 1, 0
for w in weights:
if load + w > cap:
need, load = need + 1, 0
load += w
return need <= days
lo, hi = max(weights), sum(weights)
while lo < hi:
mid = (lo + hi) // 2
if can_ship(mid):
hi = mid
else:
lo = mid + 1
return loComplexity: O(n log range). Practise: Search in Rotated Sorted Array, Koko Eating Bananas, Capacity to Ship Packages.
5. Prefix sums
Spot it: many range-sum queries, "number of subarrays summing to k".
def subarray_sum_count(nums, k):
count, total, seen = 0, 0, {0: 1}
for x in nums:
total += x
count += seen.get(total - k, 0)
seen[total] = seen.get(total, 0) + 1
return countComplexity: O(n). Practise: Subarray Sum Equals K, Range Sum Query, Product of Array Except Self.
6. Hash map counting and grouping
Spot it: frequencies, anagrams, "first unique", de-duplication.
from collections import Counter, defaultdict
def group_anagrams(words):
groups = defaultdict(list)
for w in words:
groups[tuple(sorted(w))].append(w)
return list(groups.values())Practise: Group Anagrams, Top K Frequent Elements, Longest Consecutive Sequence.
7. Monotonic stack
Spot it: "next greater / smaller element", spans, histogram areas.
def next_greater(nums):
res, stack = [-1] * len(nums), [] # stack holds indices
for i, x in enumerate(nums):
while stack and nums[stack[-1]] < x:
res[stack.pop()] = x
stack.append(i)
return resComplexity: O(n). Practise: Daily Temperatures, Largest Rectangle in Histogram, Next Greater Element II.
8. Heap / top-K
Spot it: "k largest / smallest / most frequent", merging sorted streams, running median.
import heapq
def k_largest(nums, k):
heap = []
for x in nums:
heapq.heappush(heap, x)
if len(heap) > k:
heapq.heappop(heap)
return heapComplexity: O(n log k). Practise: Kth Largest Element, Merge K Sorted Lists, Find Median from Data Stream.
9. Intervals
Spot it: meetings, bookings, overlapping ranges.
def merge(intervals):
intervals.sort()
out = [intervals[0]]
for s, e in intervals[1:]:
if s <= out[-1][1]:
out[-1][1] = max(out[-1][1], e)
else:
out.append([s, e])
return outComplexity: O(n log n). Practise: Merge Intervals, Insert Interval, Meeting Rooms II.
Stuck on which pattern applies?
In a live coding round, InterviewPilot reads the problem off your screen and returns an Explained answer — the pattern, the approach, the code and its time and space complexity — so you can talk through the reasoning, not just paste a solution.
10. Breadth-first search
Spot it: shortest path in an unweighted graph or grid, "minimum number of steps", level-order traversal.
from collections import deque
def shortest_steps(grid, start, goal):
rows, cols = len(grid), len(grid[0])
q, seen = deque([(start, 0)]), {start}
while q:
(r, c), d = q.popleft()
if (r, c) == goal:
return d
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), d + 1))
return -1Complexity: O(V + E). Practise: Rotting Oranges, Word Ladder, Binary Tree Level Order Traversal.
11. Depth-first search and backtracking
Spot it: "all combinations / permutations / subsets", islands, path existence.
def subsets(nums):
res, path = [], []
def dfs(i):
if i == len(nums):
res.append(path[:])
return
path.append(nums[i]); dfs(i + 1); path.pop() # take it
dfs(i + 1) # skip it
dfs(0)
return resComplexity: often exponential by nature (2ⁿ subsets). Practise: Number of Islands, Combination Sum, N-Queens, Word Search.
12. Topological sort
Spot it: tasks with prerequisites, build order, "is there a cycle in dependencies?"
from collections import deque, defaultdict
def course_order(n, prereqs):
graph, indeg = defaultdict(list), [0] * n
for course, pre in prereqs:
graph[pre].append(course)
indeg[course] += 1
q = deque(i for i in range(n) if indeg[i] == 0)
order = []
while q:
node = q.popleft()
order.append(node)
for nxt in graph[node]:
indeg[nxt] -= 1
if indeg[nxt] == 0:
q.append(nxt)
return order if len(order) == n else [] # [] means a cyclePractise: Course Schedule I & II, Alien Dictionary.
13. Union-Find (disjoint set)
Spot it: connected components, "are these two in the same group?", redundant connections.
parent = list(range(n))
def find(x):
while parent[x] != x:
parent[x] = parent[parent[x]] # path compression
x = parent[x]
return x
def union(a, b):
ra, rb = find(a), find(b)
if ra == rb:
return False
parent[ra] = rb
return TruePractise: Number of Provinces, Redundant Connection, Accounts Merge.
14. Dynamic programming
Spot it: "number of ways", "minimum cost", "maximum value", choices at each step that overlap. Define the state, the transition and the base case — say them out loud before coding.
def coin_change(coins, amount):
dp = [0] + [float('inf')] * amount
for a in range(1, amount + 1):
for c in coins:
if c <= a:
dp[a] = min(dp[a], dp[a - c] + 1)
return dp[amount] if dp[amount] != float('inf') else -1Practise: Climbing Stairs, House Robber, Longest Common Subsequence, Coin Change, Edit Distance.
15. Trie
Spot it: prefix searches, autocomplete, word dictionaries.
class Trie:
def __init__(self):
self.root = {}
def insert(self, word):
node = self.root
for ch in word:
node = node.setdefault(ch, {})
node['$'] = True
def starts_with(self, prefix):
node = self.root
for ch in prefix:
if ch not in node:
return False
node = node[ch]
return TruePractise: Implement Trie, Word Search II, Design Add and Search Words.
Cheat sheet: trigger → pattern
| If the problem says… | Try… |
|---|---|
| Sorted array, pair/triplet | Two pointers, binary search |
| Contiguous subarray/substring | Sliding window, prefix sums |
| Minimum value that satisfies X | Binary search on the answer |
| Top / smallest / most frequent k | Heap |
| Next greater/smaller | Monotonic stack |
| Overlapping ranges | Intervals (sort first) |
| Minimum steps, unweighted | BFS |
| All combinations/permutations | Backtracking |
| Prerequisites / ordering | Topological sort |
| Connected groups | Union-Find or DFS |
| Count ways / min cost with overlap | Dynamic programming |
| Prefix lookup | Trie |
Also read the constraints: n ≤ 20 suggests exponential backtracking is fine; n ≤ 10⁵ means you need O(n log n) or better.
How to practise so it sticks
- Pick one pattern per session; solve 5–8 problems of it back to back.
- Before coding each one, say the pattern and complexity out loud.
- Re-solve your mistakes three days later without looking.
- Mix patterns in the final two weeks so you practise recognition, not just execution.
Related reading
Frequently asked questions
Was this article useful?
Bring backup into your next round.
Install InterviewPilot, upload your resume, and walk in with structured answers a keystroke away — visible to you and nobody else.
Related reading
How to Crack a DSA Coding Round: A Practical Framework
A structured approach to data-structures-and-algorithms interviews — how to break down a problem, communicate while you solve it, and avoid the mistakes that sink otherwise-strong candidates.
30 Behavioral Interview Questions for Software Engineers (With STAR Answers)
The behavioral questions software engineers actually get asked — conflict, failure, ownership, ambiguity, leadership — grouped by what they test, with full STAR example answers and a system for preparing six stories that cover all thirty.
How to Use AI During a Live Interview: A Step-by-Step Setup
A practical walkthrough for using an AI interview assistant in a real Zoom, Teams or Google Meet interview — setup the night before, a two-minute invisibility check, the keyboard shortcuts that matter, and how to use answers without sounding scripted.
Discussion
No comments yet. Been through an interview like this? Your experience could help the next candidate.