HomeCoursesBlog
← Back to Blog
Article

The 10 Coding Interview Templates on One Page

The 10 Coding Interview Templates on One Page

TL;DR: Ten templates cover most questions asked in coding interviews. This page is all ten, with the words in a question that point to each one, the code, the complexity, and the single bug that breaks it most often. It is a reference card, not a lesson. Keep it open while you practice, and follow the deep-dive link when a template stops making sense.

Every other page on this site explains a pattern. This one does not explain anything. It is the page to keep open in a second tab while you solve problems, so you can check a template in ten seconds instead of rereading an article.

The code is Python because it is the shortest to read. The structure is the same in any language, and there is a Java version of every template if you interview in Java.

Which template does this question need?

Find the phrase closest to the question you are looking at.

The question saysUse
sorted array, pair, triplet, sum to a targetTwo Pointers
longest or shortest substring, contiguous, windowSliding Window
linked list, cycle, middle node, no extra memoryFast and Slow Pointers
sorted, or "smallest value that works"Binary Search
shortest path, level by level, nearestBFS
all combinations, all permutations, every valid boardBacktracking
top K, K largest, K most frequent, median so farHeap
intervals, meetings, overlap, mergeMerge Intervals
next greater, next smaller, largest rectangleMonotonic Stack
count the ways, minimum cost, maximum valueDynamic Programming

If nothing matches, read the last section of this page before guessing.

A lookup table mapping phrases that appear in interview questions, such as longest substring or next greater element, to the ten templates that solve them

1. Two Pointers

Use it when: the array is sorted and you are looking for a pair, a triplet, or a sum that hits a target.

def two_sum_sorted(nums, target):
    left, right = 0, len(nums) - 1
    while left < right:
        total = nums[left] + nums[right]
        if total == target:
            return [left, right]
        if total < target:
            left += 1                 # need more, move the small end up
        else:
            right -= 1                # need less, move the big end down
    return []

Complexity: O(n) time, O(1) extra space.

The one bug: using left <= right instead of left < right, which lets one element pair with itself.

Full deep dive

2. Sliding Window

Use it when: the question asks for the longest or shortest run of adjacent elements that satisfies a rule.

def longest_valid_window(s):
    counts = {}
    left = 0
    best = 0
    for right, ch in enumerate(s):
        counts[ch] = counts.get(ch, 0) + 1

        while not is_valid(counts):          # 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)   # record only while valid
    return best

Complexity: O(n) time, because each index enters and leaves the window once.

The one bug: recording the answer before the shrink loop runs. Measure the window only after it is valid again.

If the window has a fixed size, drop the while loop and remove s[right - k] on every step instead.

Full deep dive

3. Fast and Slow Pointers

Use it when: the input is a linked list or a sequence that repeats, and you may not use extra memory.

def has_cycle(head):
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
        if slow is fast:
            return True
    return False


def middle_node(head):
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
    return slow                       # slow stops at the middle

Complexity: O(n) time, O(1) space.

The one bug: checking fast.next without checking fast first, which raises an error on a list of even length.

Full deep dive

Use it when: the data is sorted, or the answer is a number and you can test whether a given value works.

def binary_search(nums, target):
    lo, hi = 0, len(nums) - 1
    while lo <= hi:
        mid = lo + (hi - lo) // 2         # avoids overflow in fixed-width languages
        if nums[mid] == target:
            return mid
        if nums[mid] < target:
            lo = mid + 1
        else:
            hi = mid - 1
    return -1


def smallest_valid(low, high, works):     # binary search on the answer
    while low < high:
        mid = low + (high - low) // 2
        if works(mid):
            high = mid                    # mid might be the answer, keep it
        else:
            low = mid + 1
    return low

Complexity: O(log n), or O(log range × cost of works) for the second form.

The one bug: mixing the two forms. The first uses lo <= hi and moves both ends past mid. The second uses low < high and keeps mid on the valid side. Pick one and do not blend them.

Full deep dive

Use it when: you need the shortest path in an unweighted graph, or you must process a tree level by level.

from collections import deque


def bfs_levels(root):
    if not root:
        return []
    queue = deque([root])
    levels = []
    while queue:
        size = len(queue)                 # freeze the level before adding to it
        level = []
        for _ in range(size):
            node = queue.popleft()
            level.append(node.val)
            for child in (node.left, node.right):
                if child:
                    queue.append(child)
        levels.append(level)
    return levels

Complexity: O(n) time, O(width) space.

The one bug: reading len(queue) inside the inner loop instead of before it, which merges every level into one.

On a graph, add a visited set and mark a node when you add it to the queue, not when you remove it.

6. Depth-First Search and Backtracking

Use it when: the question asks for all of something. All subsets, all permutations, every valid arrangement.

def backtrack(state, choices, results):
    if is_complete(state):
        results.append(list(state))       # copy, the original keeps changing
        return
    for choice in choices:
        if not is_valid(state, choice):
            continue
        state.append(choice)              # choose
        backtrack(state, choices, results)
        state.pop()                       # undo

Complexity: O(number of valid states × cost to build one). Exponential by nature, which is expected here.

The one bug: appending state instead of list(state). Every stored answer then points at the same list, and all of them end up empty.

Full deep dive

7. Top K with a Heap

Use it when: the question wants the K largest, K smallest, K most frequent, or a running median.

import heapq


def top_k_largest(nums, k):
    heap = []                             # a MIN heap, holding the k largest
    for num in nums:
        heapq.heappush(heap, num)
        if len(heap) > k:
            heapq.heappop(heap)           # drop the smallest of the k+1
    return heap

Complexity: O(n log k) time, O(k) space. Better than sorting when k is much smaller than n.

The one bug: using a max heap for the K largest. It is inverted on purpose: a min heap of size k keeps the smallest of your winners at the top, which is exactly the one to remove next.

Python's heapq is a min heap only. For a max heap, push -value.

Full deep dive

8. Merge Intervals

Use it when: the input is a list of ranges and the question mentions overlap, merging, or meeting rooms.

def merge(intervals):
    intervals.sort(key=lambda x: x[0])     # sort by start, always
    merged = [intervals[0]]
    for start, end in intervals[1:]:
        if start <= merged[-1][1]:         # overlaps the last one
            merged[-1][1] = max(merged[-1][1], end)
        else:
            merged.append([start, end])
    return merged

Complexity: O(n log n), which is the sort. The pass itself is O(n).

The one bug: writing merged[-1][1] = end instead of taking the max. One interval fully inside another then shortens the result.

Full deep dive

9. Monotonic Stack

Use it when: the question asks for the next greater element, the previous smaller element, or the largest rectangle.

def next_greater(nums):
    result = [-1] * len(nums)
    stack = []                             # holds indexes, values decreasing
    for i, num in enumerate(nums):
        while stack and nums[stack[-1]] < num:
            result[stack.pop()] = num      # num is the answer for that index
        stack.append(i)
    return result

Complexity: O(n) time, because each index is pushed once and popped once.

The one bug: storing values instead of indexes. You then cannot write the answer back to the right position.

Full deep dive

10. Dynamic Programming, top down

Use it when: the question asks to count the ways, or for a minimum cost or maximum value, and the same subproblem appears more than once.

from functools import cache


def solve(nums):
    @cache
    def best(i, remaining):
        if i == len(nums) or remaining == 0:
            return 0                       # base case first
        skip = best(i + 1, remaining)
        take = 0
        if nums[i] <= remaining:
            take = nums[i] + best(i + 1, remaining - nums[i])
        return max(skip, take)

    return best(0, target)

Complexity: O(number of distinct states × work per state).

The one bug: putting a list or a dict in the arguments of a cached function. The cache needs values it can hash, so pass an index or a tuple instead.

Write this form in the interview first. Convert to a table only if you are asked to cut memory.

Full deep dive

Want these taught in order, with problems attached? Grokking the Coding Interview builds all 42 patterns from the recognition signal through the template to 300 or so sequenced problems, in six languages.

When none of the ten fit

This happens, and guessing is the wrong response. Three checks, in order.

Is the question two patterns stacked? Many hard questions are one template feeding another. Sort the intervals, then run a heap. Build a graph, then run a topological sort. Say which two you see.

Is the input hinting at a structure you have not built yet? Prefix sums, a trie, and union-find are not templates so much as structures you set up first. If the question asks for many range sums, or many prefix lookups, or many "are these two connected" checks, build the structure and the rest becomes simple.

Can you state the brute force? Say it out loud with its complexity, then ask which part is repeated work. Nearly every optimization on this page is the answer to that one question.

Three cases where no single template fits: two templates stacked such as sorting intervals then running a heap, a structure you build first such as a prefix sum or a trie, and stating the brute force to find the repeated work

The takeaway

Ten templates, roughly forty lines of code each, cover most of what coding interviews ask. The work is not memorizing them. It is reading a question and knowing within thirty seconds which one applies, which is why every block above starts with the words that point to it rather than with the code.

Use this page while you practice. When a template stops making sense, follow its deep-dive link, then come back. The complete map of all 42 patterns shows where these ten sit among the rest, and how many problems you actually need explains why ten templates beat five hundred solved problems.

Go deeper: Grokking the Coding Interview teaches all 42 patterns (32 common and 10 advanced) for a one-time $79 with lifetime access. Short on time? Grokking 75 covers the essential problems in a six-week plan.

Frequently asked questions

Is memorizing templates enough to pass a coding interview? No, and it is not what templates are for. A template removes the mechanical part so your time goes to recognizing the pattern and handling edge cases. An interviewer will change one condition, and only understanding why the template works lets you adjust it.

How many templates do I actually need? These ten cover most questions asked at the medium level, which is where most interviews sit. There are 42 patterns in total, but the remainder are either variations on these ten or advanced patterns that appear rarely.

Should I write the template from memory or derive it each time? Derive it during practice and write it from memory during the interview. If you can only reproduce it and cannot explain why each line is there, you will not be able to adjust it when one condition changes.

What is the fastest way to learn which template a question needs? Practice recognition separately from solving. Read twenty question statements and name the pattern for each without writing any code. That takes fifteen minutes and trains the exact skill the first two minutes of an interview needs.

Do these templates work in Java and C++? Yes. The structure does not change, only the syntax and the library names. The Java version of every template and the Python version with language traps cover the differences that cost people points.

Grokking the Coding Interview
One-Stop Portal For Coding Interviews.
Follow us:
Copyright © 2025 Coding Interview All rights reserved.