DEV Community

Crackly
Crackly

Posted on

The 20 LeetCode Patterns That Cover 80% of Coding Interviews

The Problem With "Grind 500 Problems"

Every CS student hears the same advice: "Just grind LeetCode." So they do. 200 problems in, they can solve the ones they've seen — but a new problem on an interview screen still looks like Greek.

Here's what's actually happening: problems aren't random. 80% of them are variations of the same 20 patterns. Grinding without pattern recognition is memorizing answers instead of learning to reason.

This guide is the cheat sheet I wish I had before my first FAANG loop. For each pattern you'll get:

  • What it is (one sentence)
  • When it shows up in a problem (the trigger phrase)
  • A worked example
  • 3-5 LeetCode problems that use it

Save this page. Practice one pattern per day for 20 days. Most interview prep courses charge $299 for less.


The 20 Patterns

1. Two Pointers

What: Use two indices that move through an array (same direction or opposite) to avoid nested loops.

Trigger: sorted array, "find a pair", palindrome, "in place" mutation.

def two_sum_sorted(nums, target):
    left, right = 0, len(nums) - 1
    while left < right:
        s = nums[left] + nums[right]
        if s == target: return [left, right]
        if s < target: left += 1
        else: right -= 1
Enter fullscreen mode Exit fullscreen mode

Practice: Two Sum II, Valid Palindrome, 3Sum, Container With Most Water, Remove Duplicates.


2. Sliding Window

What: Maintain a contiguous range [left, right] that grows when valid, shrinks when invalid.

Trigger: "longest/shortest substring/subarray with some constraint".

def longest_no_repeat(s):
    seen, left, best = {}, 0, 0
    for right, c in enumerate(s):
        if c in seen and seen[c] >= left:
            left = seen[c] + 1
        seen[c] = right
        best = max(best, right - left + 1)
    return best
Enter fullscreen mode Exit fullscreen mode

Practice: Longest Substring Without Repeating Characters, Minimum Window Substring, Max Consecutive Ones, Longest Repeating Character Replacement.


3. Fast & Slow Pointers (Floyd's Cycle Detection)

What: One pointer moves 1 step, another moves 2. They meet if there's a cycle.

Trigger: linked list, "detect cycle", "find middle of", "happy number".

def has_cycle(head):
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
        if slow == fast: return True
    return False
Enter fullscreen mode Exit fullscreen mode

Practice: Linked List Cycle I & II, Middle of the Linked List, Happy Number.


4. Merge Intervals

What: Sort intervals, then walk through — merge when they overlap.

Trigger: "intervals", "meeting rooms", "merge ranges", "free time".

def merge(intervals):
    intervals.sort(key=lambda x: x[0])
    out = [intervals[0]]
    for start, end in intervals[1:]:
        if start <= out[-1][1]:
            out[-1][1] = max(out[-1][1], end)
        else:
            out.append([start, end])
    return out
Enter fullscreen mode Exit fullscreen mode

Practice: Merge Intervals, Insert Interval, Meeting Rooms I & II, Non-overlapping Intervals.


5. Cyclic Sort

What: When input is numbers in a range [0, n], put each at its index.

Trigger: array of 1..n, "find missing/duplicate", asks for O(1) extra space.

def find_missing(nums):
    i = 0
    while i < len(nums):
        target = nums[i] - 1
        if 0 <= target < len(nums) and nums[target] != nums[i]:
            nums[target], nums[i] = nums[i], nums[target]
        else:
            i += 1
    for j, n in enumerate(nums):
        if n != j + 1: return j + 1
    return len(nums) + 1
Enter fullscreen mode Exit fullscreen mode

Practice: Missing Number, First Missing Positive, Find All Numbers Disappeared in Array.


6. In-Place Linked List Reversal

What: Three pointers (prev, curr, next) to reverse nodes one at a time.

Trigger: "reverse linked list", "reverse in groups", "rotate list".

def reverse(head):
    prev = None
    while head:
        nxt = head.next
        head.next = prev
        prev = head
        head = nxt
    return prev
Enter fullscreen mode Exit fullscreen mode

Practice: Reverse Linked List, Reverse Linked List II, Reverse Nodes in k-Group, Rotate List.


7. Tree BFS (Level Order Traversal)

What: Queue-based, process one level at a time.

Trigger: "level", "depth", "nearest", "shortest path in tree".

from collections import deque
def level_order(root):
    if not root: return []
    q, levels = deque([root]), []
    while q:
        level = []
        for _ in range(len(q)):
            node = q.popleft()
            level.append(node.val)
            if node.left: q.append(node.left)
            if node.right: q.append(node.right)
        levels.append(level)
    return levels
Enter fullscreen mode Exit fullscreen mode

Practice: Binary Tree Level Order Traversal, Zigzag Traversal, Right Side View, Minimum Depth.


8. Tree DFS (Recursive Traversal)

What: Recurse on children, combine results at the node.

Trigger: "path sum", "depth of tree", "count nodes", "lowest common ancestor".

def max_depth(root):
    if not root: return 0
    return 1 + max(max_depth(root.left), max_depth(root.right))
Enter fullscreen mode Exit fullscreen mode

Practice: Path Sum, Path Sum II, Diameter of Binary Tree, Lowest Common Ancestor, Invert Binary Tree.


9. Binary Search

What: Repeatedly halve a sorted search space.

Trigger: sorted array, "find target", "smallest/largest such that", time limit requires O(log n).

def search(nums, target):
    lo, hi = 0, len(nums) - 1
    while lo <= hi:
        mid = (lo + hi) // 2
        if nums[mid] == target: return mid
        if nums[mid] < target: lo = mid + 1
        else: hi = mid - 1
    return -1
Enter fullscreen mode Exit fullscreen mode

Practice: Binary Search, Search in Rotated Sorted Array, Find First & Last Position, Koko Eating Bananas.


10. Top K Elements (Heap)

What: Use a heap of size K to track the top/bottom K items.

Trigger: "top K", "K most frequent", "K closest", "Kth largest".

import heapq
def top_k_frequent(nums, k):
    from collections import Counter
    return [n for n, _ in heapq.nlargest(k, Counter(nums).items(), key=lambda x: x[1])]
Enter fullscreen mode Exit fullscreen mode

Practice: Kth Largest Element, Top K Frequent Elements, K Closest Points to Origin, Find Median from Data Stream.


11. Backtracking

What: Try a choice, recurse, undo. Used to enumerate all possibilities.

Trigger: "all permutations", "all combinations", "all subsets", "N-Queens", "word search".

def permutations(nums):
    result = []
    def backtrack(path, remaining):
        if not remaining: result.append(path[:])
        for i, n in enumerate(remaining):
            path.append(n)
            backtrack(path, remaining[:i] + remaining[i+1:])
            path.pop()
    backtrack([], nums)
    return result
Enter fullscreen mode Exit fullscreen mode

Practice: Subsets, Permutations, Combinations, Word Search, N-Queens, Letter Combinations of Phone Number.


12. 0/1 Knapsack (Dynamic Programming)

What: For each item, decide include/exclude. Fill a DP table by weight.

Trigger: "choose items to maximize value under capacity", "partition array", "subset sum".

def knapsack(weights, values, capacity):
    dp = [0] * (capacity + 1)
    for w, v in zip(weights, values):
        for c in range(capacity, w - 1, -1):
            dp[c] = max(dp[c], dp[c - w] + v)
    return dp[capacity]
Enter fullscreen mode Exit fullscreen mode

Practice: Partition Equal Subset Sum, Target Sum, Last Stone Weight II, Coin Change.


13. Unbounded Knapsack / Coin Change

What: Like knapsack, but each item can be picked infinite times.

Trigger: "minimum coins", "number of ways to make change", "unlimited items".

def coin_change(coins, amount):
    dp = [float('inf')] * (amount + 1)
    dp[0] = 0
    for c in coins:
        for a in range(c, amount + 1):
            dp[a] = min(dp[a], dp[a - c] + 1)
    return dp[amount] if dp[amount] != float('inf') else -1
Enter fullscreen mode Exit fullscreen mode

Practice: Coin Change, Coin Change 2, Minimum Cost For Tickets.


14. Longest Common Subsequence (DP)

What: 2D DP on two sequences, each cell asks "do these characters match?".

Trigger: two strings/sequences, "longest common", "edit distance", "minimum operations".

def lcs(s1, s2):
    m, n = len(s1), len(s2)
    dp = [[0] * (n + 1) for _ in range(m + 1)]
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if s1[i-1] == s2[j-1]:
                dp[i][j] = 1 + dp[i-1][j-1]
            else:
                dp[i][j] = max(dp[i-1][j], dp[i][j-1])
    return dp[m][n]
Enter fullscreen mode Exit fullscreen mode

Practice: Longest Common Subsequence, Edit Distance, Delete Operation for Two Strings, Longest Palindromic Subsequence.


15. Hash Map Lookup

What: One loop builds a hash; a second (or same) loop queries in O(1).

Trigger: "find pair/triple summing to", "group anagrams", "first non-repeating", "has duplicate".

def two_sum(nums, target):
    seen = {}
    for i, n in enumerate(nums):
        if target - n in seen: return [seen[target - n], i]
        seen[n] = i
Enter fullscreen mode Exit fullscreen mode

Practice: Two Sum, Group Anagrams, Valid Anagram, Contains Duplicate, First Unique Character, Longest Consecutive Sequence.


16. Topological Sort

What: Order nodes in a DAG so every edge goes forward (dependencies before dependents).

Trigger: "course schedule", "build order", "dependency resolution", "can finish tasks".

from collections import defaultdict, deque
def can_finish(num_courses, prerequisites):
    graph, indegree = defaultdict(list), [0] * num_courses
    for a, b in prerequisites:
        graph[b].append(a); indegree[a] += 1
    q = deque([i for i in range(num_courses) if indegree[i] == 0])
    taken = 0
    while q:
        c = q.popleft(); taken += 1
        for nxt in graph[c]:
            indegree[nxt] -= 1
            if indegree[nxt] == 0: q.append(nxt)
    return taken == num_courses
Enter fullscreen mode Exit fullscreen mode

Practice: Course Schedule I & II, Alien Dictionary, Minimum Height Trees.


17. Union Find (Disjoint Set)

What: Track connected components with fast find + union.

Trigger: "connected components", "redundant connection", "number of provinces", "friend circles".

class UF:
    def __init__(self, n): self.p = list(range(n))
    def find(self, x):
        while self.p[x] != x:
            self.p[x] = self.p[self.p[x]]  # path compression
            x = self.p[x]
        return x
    def union(self, a, b):
        ra, rb = self.find(a), self.find(b)
        if ra != rb: self.p[ra] = rb
Enter fullscreen mode Exit fullscreen mode

Practice: Number of Provinces, Redundant Connection, Accounts Merge, Graph Valid Tree.


18. Monotonic Stack

What: Stack that stays increasing (or decreasing) as you push; pop anything that breaks the order.

Trigger: "next greater element", "daily temperatures", "largest rectangle in histogram".

def next_greater(nums):
    out, stack = [-1] * len(nums), []
    for i, n in enumerate(nums):
        while stack and nums[stack[-1]] < n:
            out[stack.pop()] = n
        stack.append(i)
    return out
Enter fullscreen mode Exit fullscreen mode

Practice: Next Greater Element, Daily Temperatures, Largest Rectangle in Histogram, Trapping Rain Water.


19. Dijkstra / Shortest Path

What: Priority-queue BFS from a source node, tracking cumulative weight.

Trigger: "shortest path", "minimum cost to reach", "network delay time", weighted graph.

import heapq
def dijkstra(graph, start):
    dist = {n: float('inf') for n in graph}; dist[start] = 0
    pq = [(0, start)]
    while pq:
        d, u = heapq.heappop(pq)
        if d > dist[u]: continue
        for v, w in graph[u]:
            nd = d + w
            if nd < dist[v]:
                dist[v] = nd
                heapq.heappush(pq, (nd, v))
    return dist
Enter fullscreen mode Exit fullscreen mode

Practice: Network Delay Time, Cheapest Flights Within K Stops, Path With Minimum Effort, Swim in Rising Water.


20. Bit Manipulation

What: Use bitwise operators to encode sets, toggle flags, or pack state.

Trigger: "find the one number", "XOR of pair", "count bits", "subset bitmask DP".

def single_number(nums):
    result = 0
    for n in nums:
        result ^= n
    return result  # XOR cancels pairs, leaves the unique one
Enter fullscreen mode Exit fullscreen mode

Practice: Single Number I/II/III, Counting Bits, Missing Number, Sum of Two Integers (no +), Bitmask DP problems.


The 20-Day Study Plan

Don't do more than one new pattern per day. Solve 2-3 problems per pattern to make it stick:

Days Patterns
1-4 Two Pointers, Sliding Window, Fast & Slow, Merge Intervals
5-8 Hash Map, Binary Search, Top-K Heap, Cyclic Sort
9-12 Linked List Reversal, Tree BFS, Tree DFS, Topological Sort
13-16 Backtracking, Union Find, Monotonic Stack, Dijkstra
17-20 0/1 Knapsack, Unbounded Knapsack, LCS DP, Bit Manipulation

After 20 days you'll recognize 80% of new problems within the first 30 seconds of reading them. That's the moat separating someone who solved 500 problems from someone who understands 500 problems.


Why Pattern Recognition > Memorization

Anyone can memorize "Two Sum uses a hash map." But when the interviewer hits you with "given a sorted array, find the closest pair sum to target", memorization fails — you have to recognize the underlying pattern (sorted + pair → two pointers).

That's what 20 patterns get you: not solutions, but the shape-recognition senior engineers use in real interviews.


Stop Grinding. Start Learning.

I built Crackly because LeetCode teaches you to solve problems, but doesn't teach you to think about them. Every exercise on Crackly includes:

  • AI visualizations of the algorithm in motion — watch the two-pointer slide, the sliding-window expand, the DP table fill
  • Socratic hints that guide you to the answer instead of handing it over
  • Pattern tags so you can drill by pattern, not by topic

Currently in private beta — join the waitlist at crack-ly.com. First 500 sign-ups get 3 months Pro free.

Top comments (0)