SevyDevy

Guide · DSA

How to Use DSA’s 25 Core Patterns: A Visual Guide with Creative Diagrams and Detailed Explanations

20 min readUpdated By Saket Bhatnagar

Researched and drafted with AI, reviewed and edited by Saket Bhatnagar.

In short

A detailed visual guide to the 25 core DSA patterns, covering how to identify them, when to use them, how they connect, and how to think like an interviewer using creative diagrams.

Why Most Students Stay Stuck in DSA

Most people do not struggle in DSA because they are bad at coding. They struggle because every new problem feels like a completely new universe. One day it is arrays, the next day it is trees, then suddenly graphs, then dynamic programming. Without a map, practice feels random. That is exactly why pattern-based learning matters.

The real breakthrough in DSA happens when you stop seeing questions as isolated puzzles and start seeing recurring structures. A pair-sum problem, a longest substring problem, a top-k problem, a shortest-path problem, and a minimum-cost optimization problem all usually belong to recognizable families. Once you learn those families, your brain stops panicking and starts classifying.

This blog is not just a list of 25 names. It is a pattern system. We will break down how the patterns connect, how to identify them quickly, where students usually get confused, and how to use them in interviews with confidence.

The Full Pattern Universe at a Glance

The 25 core patterns can be grouped into four big layers. The first layer teaches you how to read and optimize. The second layer teaches behavior of data structures. The third layer teaches traversal-based thinking for trees and graphs. The final layer teaches optimization-heavy reasoning.

The 25 core DSA patterns

The 25 patterns in four groups: core foundations, core data structures, trees, heaps and graphs, and advanced patterns.

Diagram connections:

  • 25 Core DSA Patterns to Core Foundations
  • Core Foundations to Core Data Structures
  • Core Data Structures to Trees, Heaps, and Graphs
  • Trees, Heaps, and Graphs to Advanced Patterns
  • Core Foundations to 01 Time & Space Complexity
  • Core Foundations to 02 Brute Force First
  • Core Foundations to 03 Arrays
  • Core Foundations to 04 Strings
  • Core Foundations to 05 Hashing
  • Core Foundations to 06 Two Pointers
  • Core Foundations to 07 Sliding Window
  • Core Foundations to 08 Prefix Sum
  • Core Foundations to 09 Binary Search
  • Core Foundations to 10 Sorting
  • Core Data Structures to 11 Stack
  • Core Data Structures to 12 Queue / Deque
  • Core Data Structures to 13 Linked List
  • Core Data Structures to 14 Recursion
  • Core Data Structures to 15 Backtracking
  • Trees, Heaps, and Graphs to 16 Tree DFS
  • Trees, Heaps, and Graphs to 17 Tree BFS / Level Order
  • Trees, Heaps, and Graphs to 18 BST
  • Trees, Heaps, and Graphs to 19 Heap / Priority Queue
  • Trees, Heaps, and Graphs to 20 Graph BFS
  • Trees, Heaps, and Graphs to 21 Graph DFS
  • Trees, Heaps, and Graphs to 22 Union Find
  • Trees, Heaps, and Graphs to 23 Topological Sort
  • Advanced Patterns to 24 Greedy
  • Advanced Patterns to 25 Dynamic Programming

What Pattern Thinking Actually Means

Pattern thinking means you do not begin with code. You begin with recognition. You look at the shape of the input, the kind of output required, the constraints, and the hidden signals in the wording. That lets you narrow the solution space before you write a single line.

  • If the input is sorted, your brain should immediately consider binary search or two pointers.
  • If the question asks for the longest or shortest valid contiguous part, sliding window should become a top candidate.
  • If repeated range sums or cumulative counts matter, prefix sum should light up.
  • If you need fast lookup, duplicate detection, or frequency counts, hashing is often the first useful lever.
  • If the problem is about levels, shortest moves, or minimum edges in an unweighted graph, BFS is often stronger than DFS.
  • If the problem keeps repeating similar states and brute force recomputes them, dynamic programming is usually nearby.

How to Read a DSA Problem Like an Engineer

A lot of students fail interviews not because they do not know the pattern, but because they do not know how to detect it fast. The right approach is to ask a small fixed set of questions in the same order every time.

Pattern selection engine

Read the input shape first, then the goal; each signal points to a likely pattern. When unsure, start with brute force and optimize.

Diagram connections:

  • Read the problem carefully to What is the input shape?
  • What is the input shape? to What is the goal? (Array / String)
  • What is the input shape? to Think pointer manipulation (Linked List)
  • What is the input shape? to Think Tree DFS or Tree BFS (Tree)
  • What is the input shape? to Think Graph BFS DFS Union Find or Topological Sort (Graph)
  • What is the input shape? to Think Sorting Greedy Heap (Intervals)
  • What is the input shape? to Think Backtracking (Choice generation)
  • What is the goal? to Hashing (Fast lookup / duplicates / frequency)
  • What is the goal? to Two Pointers (Pair / partition / in-place scan)
  • What is the goal? to Sliding Window (Longest or shortest valid range)
  • What is the goal? to Prefix Sum (Many range queries / cumulative values)
  • What is the goal? to Binary Search (Sorted / monotonic / search on answer)
  • What is the goal? to Sorting (Need ordering to expose structure)
  • What is the goal? to Dynamic Programming (Repeated subproblems)
  • What is the goal? to Greedy (Local best move seems provable)
  • Read the problem carefully to Start with brute force if unclear
  • Start with brute force if unclear to Then optimize with the chosen pattern

Layer 1: Core Foundations

This layer is the base of everything. If you are weak here, advanced topics will feel harder than they really are. These patterns teach you how to evaluate efficiency, simplify a problem, and understand the common shapes hidden in arrays and strings.

  • Time & Space Complexity: This is your reality check. It tells you whether your solution is affordable in the given constraints. Strong candidates think about complexity before coding and then verify it again after coding.
  • Brute Force First: The goal is not to worship brute force. The goal is to get a correct baseline. Once the brute-force path is visible, optimization becomes logical instead of magical.
  • Arrays: Arrays are the most common interview input. The moment you see ordered positions, contiguous segments, index-based transitions, or subarray conditions, array thinking becomes primary.
  • Strings: Strings are essentially character arrays with extra rules. Substring windows, frequency counts, matching, parsing, and pattern validation often begin here.
  • Hashing: HashMap and HashSet convert expensive repeated searches into fast lookups. If a problem says duplicate, seen-before, grouping, complement, count, or quick membership, hashing is often involved.
  • Two Pointers: Two pointers replace nested loops in many sorted or constrained traversal problems. They are excellent for pair sums, partitioning, reverse scans, and in-place edits.
  • Sliding Window: This is one of the most profitable interview patterns. Whenever the question is about a contiguous valid range that expands and shrinks under conditions, think sliding window.
  • Prefix Sum: Prefix sum is the pattern of cumulative memory. Instead of recomputing sums or counts across ranges, you precompute once and answer quickly.
  • Binary Search: Binary search is not limited to finding an element in a sorted array. It also appears when the answer space is monotonic, meaning a candidate answer can be tested as valid or invalid.
  • Sorting: Many questions become easier after sorting because hidden structure becomes visible. Sorting often unlocks greedier reasoning, interval merging, and cleaner comparisons.

How the Foundation Patterns Connect

The foundation patterns are not isolated. They constantly combine. Sorting can make two pointers possible. Hashing can replace nested loops. Prefix sums can optimize brute force. Binary search can be applied after sorting or even on the answer space itself.

How the foundation patterns combine

Brute force leads to hashing, prefix sum and sorting; sorting unlocks two pointers and greedy; sliding window and binary search have their own needs.

Diagram connections:

  • Brute Force to Hashing reduces repeated lookup
  • Brute Force to Prefix Sum reduces repeated range work
  • Brute Force to Sorting reveals hidden order
  • Sorting reveals hidden order to Two Pointers becomes possible
  • Sorting reveals hidden order to Greedy reasoning becomes easier
  • Sliding Window to Often uses HashMap / frequency tracking
  • Binary Search to Needs monotonic structure or sorted state

In code: brute force vs hashing

Question: does any pair in the list add up to a target? Brute force checks every pair with two loops.

js
// Brute force: check every pair with two loops
function hasPairSum(nums, target) {
  for (const [i, a] of nums.entries()) {
    for (const b of nums.slice(i + 1)) {
      if (a + b === target) return true
    }
  }
  return false
}

Hashing solves the same question in one loop. The set remembers every number you have already seen.

js
// Same question, one loop: remember what you have seen
function hasPairSum(nums, target) {
  const seen = new Set()
  for (const x of nums) {
    if (seen.has(target - x)) return true
    seen.add(x)
  }
  return false
}

In code: binary search

In a sorted array, look at the middle item. Then throw away the half that cannot hold the target.

js
function binarySearch(arr, target) {
  let lo = 0, hi = arr.length - 1
  while (lo <= hi) {
    const mid = Math.floor((lo + hi) / 2)
    if (arr[mid] === target) return mid
    if (arr[mid] < target) lo = mid + 1   // go right
    else hi = mid - 1                     // go left
  }
  return -1
}

Sliding Window, Two Pointers, and Prefix Sum: The Trio Students Confuse the Most

These three are heavily related, which is why beginners often mix them up. The clean distinction is this: two pointers is a broad movement strategy, sliding window is a special kind of two-pointer pattern for contiguous valid ranges, and prefix sum is about precomputed cumulative information rather than live expansion and shrinking.

Two pointers vs sliding window vs prefix sum

Three patterns for contiguous, range and scan problems, and the signals that tell them apart.

Diagram connections:

  • Contiguous / range / scan problems to Two Pointers
  • Contiguous / range / scan problems to Sliding Window
  • Contiguous / range / scan problems to Prefix Sum
  • Two Pointers to Use when two indices move with purpose
  • Two Pointers to Often sorted arrays or pair logic
  • Sliding Window to Use when window expands and shrinks
  • Sliding Window to Need longest or shortest valid range
  • Sliding Window to Condition changes live as pointers move
  • Prefix Sum to Use when many range queries exist
  • Prefix Sum to Need cumulative totals or counts
  • Prefix Sum to Precompute once, answer fast

A good interview habit is to listen for keywords. If the question says longest substring without repeating characters, sliding window is a strong candidate. If it says find two numbers in a sorted array with target sum, two pointers fits. If it says answer many sum queries over ranges, prefix sum becomes natural.

In code: sliding window

Find the longest part of a word with no repeating letter. The window grows on the right and shrinks from the left.

js
function longestUnique(s) {
  const seen = new Set()
  let left = 0, best = 0
  for (const [right, ch] of [...s].entries()) {
    while (seen.has(ch)) seen.delete(s[left++])   // shrink from the left
    seen.add(ch)                                  // grow on the right
    best = Math.max(best, right - left + 1)
  }
  return best
}

Layer 2: Core Data Structures

This layer teaches you to think in terms of behavior, not only data shape. The question is no longer just what the input looks like. The question becomes how values must enter, leave, pause, reverse, nest, or branch over time.

  • Stack: Think of a stack when the last unresolved thing must be handled first. Parentheses checking, undo systems, monotonic stack problems, and next greater element all live here.
  • Queue / Deque: A queue is for first-in-first-out processing, while a deque allows both ends. BFS, scheduling, and sliding-window maximum are classic use cases.
  • Linked List: Linked lists test pointer comfort. Reversal, cycle detection, middle node, merge, and pointer rewiring are the dominant themes.
  • Recursion: Recursion is not just a coding style. It is a way of trusting the same logic on smaller copies of the problem. Trees, divide-and-conquer, and branching exploration rely heavily on it.
  • Backtracking: Backtracking is controlled exploration. You choose, go deeper, and undo. It powers subsets, permutations, combinations, path generation, N-Queens, Sudoku, and similar search problems.

Behavior Lens: Which Structure Fits the Problem?

The easiest way to identify these patterns is to stop staring at the input and instead observe how the process must behave. Does the latest unresolved thing matter most? That is a stack signal. Do you need level-by-level processing? That is queue behavior. Do you need to try all paths and undo wrong choices? That is backtracking.

Behavior-based data structure selection

Name the behavior the problem needs; each behavior points to one structure.

Diagram connections:

  • Problem behavior to What kind of behavior is needed?
  • What kind of behavior is needed? to Stack (Last unresolved item first)
  • What kind of behavior is needed? to Queue (First item to enter should leave first)
  • What kind of behavior is needed? to Deque (Need both ends)
  • What kind of behavior is needed? to Linked List (Pointer rewiring / node movement)
  • What kind of behavior is needed? to Recursion (Same logic on smaller copies)
  • What kind of behavior is needed? to Backtracking (Try, explore, undo)

In code: stack

Do the brackets match? Push every open bracket. Every close bracket must match the top of the stack.

js
// Stack: do the brackets match?
function isValid(s) {
  const pairs = { ')': '(', ']': '[', '}': '{' }
  const stack = []
  for (const ch of s) {
    if (!pairs[ch]) stack.push(ch)                      // open: push
    else if (stack.pop() !== pairs[ch]) return false    // close: must match top
  }
  return stack.length === 0
}

In code: linked list

Reverse a linked list by flipping one arrow at a time. Always save the next link before you change it.

js
function reverseList(head) {
  let prev = null, cur = head
  while (cur) {
    const next = cur.next   // save the link first
    cur.next = prev         // flip the arrow
    prev = cur
    cur = next
  }
  return prev               // new head
}

In code: backtracking

List every subset of an array. Choose an item, go deeper, then undo the choice and try without it.

js
function subsets(nums, i = 0, pick = [], out = []) {
  if (i === nums.length) {                 // base case
    out.push([...pick])
    return out
  }
  pick.push(nums[i])                       // choose
  subsets(nums, i + 1, pick, out)          // explore
  pick.pop()                               // undo
  return subsets(nums, i + 1, pick, out)   // try without it
}

Layer 3: Trees, Heaps, and Graphs

This is the layer where many learners lose confidence, but the truth is simpler than it looks. Most tree and graph problems reduce to a limited number of traversals plus a few structural ideas. The big win is learning what each traversal naturally gives you.

  • Tree DFS: Ideal for recursive logic such as subtree checks, height, diameter, path sum, balance, or tree-based DP.
  • Tree BFS / Level Order: Ideal for level-wise views, minimum depth, shortest steps on a tree, and side views.
  • BST: The binary search tree adds ordering. In-order traversal becomes powerful, and range queries, insert, search, predecessor, and successor reasoning become natural.
  • Heap / Priority Queue: Heaps are about efficient access to the smallest or largest current candidate. Use them for Top K, kth element, scheduling, merging sorted streams, and streaming median variants.
  • Graph BFS: Best for shortest path in unweighted graphs, layered exploration, minimum moves, and transformation problems.
  • Graph DFS: Best for full exploration, connected components, cycle detection, path existence, and flood-fill style logic.
  • Union Find: Best when you need to merge and query connectivity repeatedly. It is extremely useful for redundant edges, connected groups, and dynamic connectivity.
  • Topological Sort: Best when dependencies matter and an order must respect them. Course schedule and DAG processing are classic signs.

Tree DFS vs Tree BFS: One Structure, Two Mindsets

A tree gives you two very different ways to think. DFS goes deep and is natural for recursive property calculation. BFS moves level by level and is natural when levels themselves are the point.

A simple binary tree

Seven nodes, used below to compare depth-first and breadth-first traversal.

Diagram connections:

  • 1 to 2
  • 1 to 3
  • 2 to 4
  • 2 to 5
  • 3 to 6
  • 3 to 7

Tree DFS vs tree BFS

Depth-first goes deep and suits subtree properties; breadth-first goes level by level and suits distance and level questions.

Diagram connections:

  • Tree DFS to Usually recursive
  • Tree DFS to Good for subtree properties
  • Tree DFS to Examples
  • Tree BFS / Level Order to Usually queue-based
  • Tree BFS / Level Order to Good for distance / level questions
  • Tree BFS / Level Order to Examples
  • Tree DFS: Go deep first
  • Examples: height, diameter, path sum
  • Tree BFS / Level Order: Go level by level
  • Examples: minimum depth, right view

In code: tree DFS and tree BFS

DFS finds the height of a tree with recursion. BFS reads the values level by level with a queue.

js
// DFS: go deep with recursion
const height = (n) => (n ? 1 + Math.max(height(n.left), height(n.right)) : 0)
function levelOrder(root) {              // BFS: level by level with a queue
  const queue = root ? [root] : []
  for (const n of queue) {               // the queue grows while you loop
    if (n.left) queue.push(n.left)
    if (n.right) queue.push(n.right)
  }
  return queue.map((n) => n.val)
}

In code: heap

Keep only the 3 largest numbers from a stream. JavaScript has no built-in heap, so this example uses Python.

python
import heapq            # Python has a heap built in
top = []
for n in [5, 1, 8, 3, 9]:
    heapq.heappush(top, n)
    if len(top) > 3:
        heapq.heappop(top)   # throw out the smallest
print(sorted(top))           # [5, 8, 9] = the 3 largest

Graph Problems Become Easier When You Ask the Right Question

Students often say graph problems all look different. They do not. The story changes, but the engine is often the same. Islands, flight paths, social connections, dependencies, transformations, and grids can all reduce to a graph model. The winning move is to ask what the graph problem actually wants from you.

Graph pattern decision tree

Ask what the real goal is; each answer points to BFS, DFS, union find or topological sort.

Diagram connections:

  • Graph Problem to What is the real goal?
  • What is the real goal? to Graph BFS (Shortest path in unweighted graph)
  • What is the real goal? to Graph DFS (Explore all reachable nodes)
  • What is the real goal? to Union Find (Check if nodes belong to same group)
  • What is the real goal? to Topological Sort (Respect dependency order)
  • Graph BFS: Levels matter
  • Graph DFS: Components / cycles / existence matter
  • Union Find: Dynamic connectivity matters
  • Topological Sort: DAG ordering matters

One of the biggest interview upgrades is knowing that BFS is usually better than DFS for shortest path in an unweighted graph, because BFS explores by layers and therefore reaches the minimum-edge answer first. That one idea alone fixes a huge number of graph mistakes in interviews.

In code: graph BFS

BFS gives the fewest steps from one node to every other node in an unweighted graph. Nearer nodes enter the queue first.

js
function stepsFrom(graph, start) {
  const dist = { [start]: 0 }, queue = [start]
  for (const node of queue) {
    const fresh = graph[node].filter((next) => !(next in dist))
    for (const next of fresh) dist[next] = dist[node] + 1
    queue.push(...fresh)                 // nearer dots go in the queue first
  }
  return dist                            // fewest steps to every dot
}

Layer 4: Advanced Patterns

The final layer is about optimization under deeper reasoning. Greedy and dynamic programming are often treated as scary topics, but the real difference is clarity of decision-making. Greedy wins when a local choice can be proven safe. Dynamic programming wins when you must remember and compare overlapping states.

  • Greedy: Use when each local best move helps build the global best answer, often in interval scheduling, resource allocation, activity selection, or proof-based minimum/maximum problems.
  • Dynamic Programming: Use when brute force recomputes the same subproblems again and again, especially in counting ways, minimum cost, maximum value, longest subsequence, knapsack, and state-transition problems.

Greedy vs Dynamic Programming

A lot of confusion disappears when you understand this clearly. Greedy is not 'easy DP' and DP is not 'hard greedy.' They solve different confidence levels of optimization. Greedy trusts one move now. DP remembers many possibilities because trusting one move is unsafe.

Greedy vs dynamic programming

If one local best move can be proven safe, use greedy; if subproblems repeat, use dynamic programming; otherwise look elsewhere.

Diagram connections:

  • Optimization Problem to Can one local best move be proven safe?
  • Can one local best move be proven safe? to Greedy (Yes)
  • Can one local best move be proven safe? to Do subproblems repeat? (No)
  • Do subproblems repeat? to Dynamic Programming (Yes)
  • Do subproblems repeat? to Try brute force, graph, or other structure-driven patterns (No)

In code: where greedy fails and DP wins

Make 6 with coins 1, 3 and 4. Greedy grabs the biggest coin first and needs three coins. DP tries every coin for every amount and finds two.

js
// Coins [1, 3, 4], make 6: greedy takes 4+1+1, DP finds 3+3
function minCoins(coins, amount) {
  const best = [0]                       // base case: 0 coins make 0
  while (best.length <= amount) {
    const a = best.length                // state: fewest coins for amount a
    const tries = coins.filter((c) => c <= a).map((c) => best[a - c] + 1)
    best.push(Math.min(...tries))        // transition: try each coin
  }
  return best[amount]
}

The Full Interview Workflow: From Confusion to Pattern to Solution

A strong candidate does not just know patterns. A strong candidate follows a stable workflow. That workflow makes thinking visible to the interviewer and keeps your solution structured even under pressure.

Interview problem-solving workflow

From reading the problem to discussing edge cases and trade-offs, one step at a time.

Diagram connections:

  • Read the problem to Clarify input, output, and constraints
  • Clarify input, output, and constraints to Identify shape and signals
  • Identify shape and signals to Choose likely pattern
  • Choose likely pattern to State brute-force approach
  • State brute-force approach to Optimize using pattern
  • Optimize using pattern to Write code
  • Write code to Dry run on sample
  • Dry run on sample to Explain time and space complexity
  • Explain time and space complexity to Discuss edge cases and trade-offs

A Study Roadmap for Mastering the 25 Patterns

Do not try to master all 25 at once. That usually turns learning into noise. Instead, learn in layers, starting with recognition, then practice, then mixed recall. The goal is not to finish a list. The goal is to train recognition speed and solution stability.

  • Phase 1: Learn complexity, brute force thinking, arrays, strings, hashing, and sorting. This is where most interview problems begin.
  • Phase 2: Add two pointers, sliding window, prefix sum, and binary search. These are high-frequency optimization patterns.
  • Phase 3: Learn stack, queue, linked list, recursion, and backtracking with behavior-based understanding.
  • Phase 4: Learn tree DFS, tree BFS, BST, heap, graph BFS, graph DFS, Union Find, and topological sort.
  • Phase 5: Learn greedy and dynamic programming only after you are comfortable recognizing repeated subproblems and local-vs-global decisions.
  • Phase 6: Practice mixed questions where the first task is to identify the pattern before solving.

Suggested pattern learning roadmap

Six phases, from foundations to mixed interview drills.

Diagram connections:

  • Foundations to Optimization Basics
  • Optimization Basics to Behavioral Structures
  • Behavioral Structures to Trees and Graphs
  • Trees and Graphs to Advanced Optimization
  • Advanced Optimization to Mixed Interview Drills
  • Foundations: Phase 1
  • Optimization Basics: Phase 2
  • Behavioral Structures: Phase 3
  • Trees and Graphs: Phase 4
  • Advanced Optimization: Phase 5
  • Mixed Interview Drills: Phase 6

Mistakes That Keep Students from Getting Better

The reason many people practice for months without real progress is not lack of effort. It is repeated pattern mistakes. The same mistakes show up again and again across interviews.

  • Memorizing final code without understanding the signal that made the pattern correct.
  • Skipping brute force and trying to jump directly into optimized code, which causes confusion and weak explanation.
  • Mixing up sliding window, two pointers, and prefix sum because all three involve ranges.
  • Using DFS when BFS is needed for shortest path in an unweighted graph.
  • Ignoring sorting even when sorting would reveal the structure required for two pointers or greedy logic.
  • Forcing dynamic programming without clearly defining state, transition, and base cases.
  • Practicing too many random questions without grouping them by pattern and comparing why different patterns fit.

How Interviewers See Pattern Knowledge

Interviewers do not just look for correct code. They look for organized reasoning. When you say, 'This is a sliding-window problem because I need the longest valid contiguous substring and the condition changes as the range expands,' that sounds fundamentally different from guessing. Pattern language makes your thought process visible.

That is why pattern-based preparation is so powerful. It helps you recover when stuck, it helps you explain trade-offs, and it helps the interviewer trust that your solution is not accidental. In real interviews, that trust matters a lot.

Final Takeaway

The 25 core DSA patterns are not a cheat sheet to memorize. They are a system for thinking. Once you truly understand them, questions stop looking random and start looking structured. You become faster at recognition, clearer in explanation, and stronger in optimization.

If you want real growth, do not chase hundreds of disconnected questions. Master the patterns, understand the signals, and practice explaining why a pattern fits. That is what turns DSA from fear into fluency.

Practise this with Lala

Practise