All levels

Data Structures and Algorithms Interview Prep

Twenty-one chapters from how to run a coding interview to every core pattern: arrays, windows, stacks, trees, graphs, backtracking and dynamic programming, with tested Python and diagrams.

Chapter 21 of 21Advanced and strategy · Study Plan, Templates and Mock Playbook

Study Plan, Templates and Mock Interview Playbook

This last chapter turns the material into a routine. It gives a study plan you can adapt to the time you have, a one-page template sheet to rebuild from memory, a table for recognising problems, and a playbook for the final week and the interview itself.

1. How to use your time

Most people prepare badly in one of two ways: they read solutions without struggling first, or they grind hundreds of problems without ever revisiting a mistake. What builds skill is attempt, struggle, check, then redo from memory after a gap.

A reliable loop for each problem:

  1. Attempt for 20 to 30 minutes with no hints. Say your reasoning aloud or write it down.
  2. If stuck, read only the pattern name or the first hint, then try again for 10 minutes.
  3. Read a full solution. Compare it with yours and note the insight you missed, in one sentence.
  4. Redo the problem from scratch after 2 days, then after 7 days, without looking.
  5. Keep a mistake log: the problem, the pattern, the insight, the bug you made.

Aim for fewer problems, understood deeply. Sixty to ninety well-reviewed problems across all patterns beat three hundred skimmed ones.

2. A plan by time available

TimeFocus
2 weeksArrays and hashing, two pointers and windows, stacks, binary search, trees, BFS and DFS, basic DP. Skip tries, segment trees and bit tricks unless the role needs them. 3 problems a day plus review.
6 weeksAll patterns once in order, then a second pass over the ones you got wrong. Add two mock interviews a week from week 4.
12 weeksEverything, plus hard problems, a full second pass, system design basics if the role needs them, and weekly timed mocks.

A six-week sketch:

WeekTopicsOutput
1Complexity, arrays and hashing, two pointers, sliding window15 problems, mistake log started
2Stacks, queues, binary search, linked lists15 problems
3Trees, BST, heaps, sorting and intervals15 problems, one mock
4Graphs (BFS, DFS, grids, topological sort, union-find), shortest paths12 problems, two mocks
5Recursion and backtracking, dynamic programming (1D then 2D)15 problems, two mocks
6Greedy, tries, design problems, revisit the mistake log, timed mocksWeak topics redone, two or three mocks

3. The one-page template sheet

If you can write each of these from memory in a minute, you have the patterns.

Binary search on a sorted array (first index where condition is true):

def first_true(lo, hi, ok):                # ok is monotone: False ... False True ... True
    while lo < hi:
        mid = (lo + hi) // 2
        if ok(mid):
            hi = mid
        else:
            lo = mid + 1
    return lo

assert first_true(0, 10, lambda x: x * x >= 50) == 8

Sliding window (longest substring satisfying a condition):

def longest_window(s, max_distinct):
    counts, left, best = {}, 0, 0
    for right, ch in enumerate(s):
        counts[ch] = counts.get(ch, 0) + 1
        while len(counts) > max_distinct:          # shrink until valid again
            counts[s[left]] -= 1
            if counts[s[left]] == 0:
                del counts[s[left]]
            left += 1
        best = max(best, right - left + 1)
    return best

assert longest_window("eceba", 2) == 3

BFS on a graph (shortest path in steps):

from collections import deque

def bfs_distance(graph, start, goal):
    seen, queue = {start}, deque([(start, 0)])
    while queue:
        node, d = queue.popleft()
        if node == goal:
            return d
        for nxt in graph[node]:
            if nxt not in seen:
                seen.add(nxt)
                queue.append((nxt, d + 1))
    return -1

g = {"a": ["b", "c"], "b": ["d"], "c": ["d"], "d": []}
assert bfs_distance(g, "a", "d") == 2 and bfs_distance(g, "d", "a") == -1

Backtracking (all subsets):

def subsets(nums):
    result, path = [], []
    def go(i):
        if i == len(nums):
            result.append(path[:])
            return
        go(i + 1)                          # skip nums[i]
        path.append(nums[i]); go(i + 1); path.pop()   # take nums[i]
    go(0)
    return result

assert sorted(map(tuple, subsets([1, 2, 3]))) == sorted([(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)])

Dynamic programming (1D, state is the index):

def house_robber(nums):
    take, skip = 0, 0
    for x in nums:
        take, skip = skip + x, max(take, skip)
    return max(take, skip)

assert house_robber([2, 7, 9, 3, 1]) == 12

Monotonic stack (next greater element):

def next_greater(nums):
    result, stack = [-1] * len(nums), []
    for i, x in enumerate(nums):
        while stack and nums[stack[-1]] < x:
            result[stack.pop()] = x
        stack.append(i)
    return result

assert next_greater([2, 1, 2, 4, 3]) == [4, 2, 4, -1, -1]

Heap, top k frequent:

import heapq
from collections import Counter

def top_k_frequent(nums, k):
    return [x for x, _ in heapq.nlargest(k, Counter(nums).items(), key=lambda p: p[1])]

assert set(top_k_frequent([1, 1, 1, 2, 2, 3], 2)) == {1, 2}

4. Recognising the pattern

Phrase in the problemFirst thing to try
"Sorted array", "find in logarithmic time"Binary search
"Contiguous subarray or substring with a property"Sliding window, or prefix sums with a hash map
"Pair or triple that sums to ..."Sort and two pointers, or hash set
"Next greater or smaller", "span", "histogram"Monotonic stack
"Top k", "k-th largest", "merge k lists"Heap
"Shortest path, fewest steps" (unweighted)BFS
"Shortest path with weights"Dijkstra (non-negative), Bellman-Ford otherwise
"Connected components, are these connected, dynamic merges"Union-find
"Order with dependencies", "prerequisites"Topological sort
"All combinations, permutations, subsets", "place under constraints"Backtracking
"Minimum or maximum, count ways, can you reach" with overlapping subproblemsDynamic programming
"Intervals", "meetings", "schedule"Sort, then sweep or greedy
"Prefix of strings", "autocomplete", "word search"Trie
"Design a structure with operations"Hash map plus linked list or array
"Subarray sum equals k" including negativesPrefix sum with hash map
"Single number, powers of two, subsets as masks"Bit manipulation

5. Complexity quick reference

OperationTypical cost
Hash map or set lookup, insert average
Sort
Heap push, pop
Binary search
BFS or DFS on a graph
Dijkstra with a heap
Subsets of items
Permutations of items
2D DP over two strings of lengths and

If your constraint is , think exponential (subsets, bitmask). If , you need or better. If , is fine.

6. The final week

  • Stop learning new patterns two or three days before. Revise the mistake log and redo problems you missed.
  • Do timed, spoken mocks, ideally with another person, in a plain editor without autocomplete.
  • Rehearse your opening: restate the problem, ask two clarifying questions, give examples, propose brute force, then improve.
  • Sleep. Tired candidates make off-by-one errors that rested ones do not.
  • Prepare your environment: stable connection, charged laptop, a pen and paper, water, and a tested video setup.

7. Mock interview playbook

During a 45-minute round:

MinutesWhat to do
0 to 5Restate the problem. Ask about input size, duplicates, negative numbers, empty input, whether the data is sorted. Write a small example and its answer.
5 to 10State a brute force and its complexity. Find the bottleneck. Propose the better approach and ask whether the interviewer agrees before coding.
10 to 30Code cleanly, with meaningful names. Narrate key decisions. Avoid silent stretches.
30 to 40Trace a test case by hand. Then test the edges: empty, single element, duplicates, the largest case. Fix bugs calmly.
40 to 45State time and space complexity. Mention possible improvements. Leave time for questions.

If you are stuck: say what you have tried and what is blocking you. Interviewers want to see how you recover. Try a smaller example, a brute force, or ask what property of the input you may be missing. Taking a hint is normal and costs less than silence.

If you find a bug late: say so, locate it, fix it. Do not defend broken code.

If you have seen the problem before: say so honestly and still walk through your reasoning. Pretending to discover a memorised solution usually shows.

8. Questions to ask your interviewer

At the end, ask things you want to know: what the team is building now, how engineers are onboarded, how the team handles code review, and what a strong first six months looks like. Avoid questions you could answer from a website, and avoid asking about compensation at this stage unless the recruiter opens it.

9. Common mistakes in preparation

  • Reading solutions too early, which trains recognition, not recall.
  • Never reviewing. Without spaced repetition, most of what you solved is gone in a month.
  • Memorising solutions instead of patterns, which fails on variations.
  • Skipping complexity analysis, which interviewers always ask about.
  • Practising only in an IDE with autocomplete, then freezing in a plain editor.
  • Not practising speaking. Thinking aloud is a skill, and it needs reps.
  • Ignoring weak areas (usually graphs or DP) because they feel bad.
  • Cramming the night before, which adds anxiety and little knowledge.

10. A closing checklist

  • I can state the time and space complexity of every solution I write.
  • I can write the templates in section 3 from memory.
  • I ask clarifying questions and give examples before coding.
  • I can explain why my solution is correct, not only what it does.
  • I test with an empty input, a single element and a duplicate-heavy input.
  • I keep a mistake log and revisit it every week.
  • I have done at least five full mock interviews under time pressure.
Header Logo