Home/Blog/5 Patterns That Crack 90% of DSA Interview Questions
DSAInterviewArraysAlgorithms

5 Patterns That Crack 90% of DSA Interview Questions

Most DSA problems are variations of just 5 core patterns. Learn them once, and you can solve hundreds of problems β€” even ones you've never seen before.

S
SCS TeamΒ·10 March 2026Β·12 min read

Every year, hundreds of thousands of Indian engineering students study DSA for placements. Most of them memorise solutions. A few understand patterns. Only the second group does well in interviews they haven't prepared for.

This article teaches you the 5 patterns. After reading, you won't just know how to solve Two Sum β€” you'll know why the approach works and how to apply the same thinking to 50 other problems.


Pattern 1: Two Pointers

What it solves: Problems on sorted arrays or strings where you need to find a pair, triplet, or window that satisfies a condition.

The core idea: Start one pointer at the left end and one at the right end. Move them toward each other based on the current sum/condition. This turns O(nΒ²) brute force into O(n).

When to recognise it: The problem involves a sorted array and asks you to find elements that sum to a target, or asks about palindromes, or involves removing duplicates in-place.

Example: Two Sum II (sorted input)

def two_sum(numbers, target):
    left, right = 0, len(numbers) - 1
    
    while left < right:
        current_sum = numbers[left] + numbers[right]
        
        if current_sum == target:
            return [left + 1, right + 1]  # 1-indexed
        elif current_sum < target:
            left += 1   # need bigger sum β†’ move left pointer right
        else:
            right -= 1  # need smaller sum β†’ move right pointer left
    
    return []

Why it works: Because the array is sorted, if the sum is too small, the only way to increase it is to move the left pointer right. If it's too big, move the right pointer left. You never need to check pairs twice.

Problems to practice

  • Valid Palindrome
  • Container With Most Water
  • 3Sum (sort first, then two pointers for each element)
  • Trapping Rain Water

Pattern 2: Sliding Window

What it solves: Subarray or substring problems where you need to find the longest, shortest, or optimal contiguous sequence satisfying a condition.

The core idea: Maintain a window with two pointers (left and right). Expand right to grow the window. Shrink from the left when the window violates the condition. This avoids recomputing the sum/state of overlapping windows.

When to recognise it: Keywords like "subarray," "substring," "contiguous," "maximum length," "minimum length."

Example: Longest Substring Without Repeating Characters

def length_of_longest_substring(s):
    char_set = set()
    left = 0
    max_len = 0
    
    for right in range(len(s)):
        # Shrink window until no duplicate
        while s[right] in char_set:
            char_set.remove(s[left])
            left += 1
        
        char_set.add(s[right])
        max_len = max(max_len, right - left + 1)
    
    return max_len

The template to remember:

  1. Add s[right] to your window state
  2. While window is invalid: remove s[left], move left right
  3. Update your answer using the current window

Problems to practice

  • Maximum Sum Subarray of Size K (fixed window)
  • Permutation in String
  • Minimum Window Substring (hard)
  • Max Consecutive Ones III

Pattern 3: Fast & Slow Pointers (Floyd's Algorithm)

What it solves: Cycle detection in linked lists or sequences. Also useful for finding the middle of a linked list.

The core idea: Move one pointer one step at a time ("slow") and another two steps at a time ("fast"). If there's a cycle, they'll eventually meet inside it. If there's no cycle, the fast pointer reaches the end.

When to recognise it: Linked list cycle problems, finding the middle of a linked list, duplicate detection in arrays with values in range [1, n].

Example: Detect Cycle in Linked List

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

Why they always meet: If a cycle exists, the fast pointer gains one step per iteration on the slow pointer (it moves 2, slow moves 1 = net gain of 1). Eventually the gap closes to 0 β€” they meet.

Finding the middle of a linked list

def find_middle(head):
    slow = head
    fast = head
    
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
    
    return slow  # when fast reaches end, slow is at middle

Problems to practice

  • Happy Number (apply fast/slow to the digit-sum sequence)
  • Find the Duplicate Number
  • Linked List Cycle II (find the start of the cycle)
  • Reorder List (split at middle first)

Pattern 4: Hash Map for O(1) Lookup

What it solves: Any problem where brute force involves nested loops searching for a complement, frequency, or previously seen value.

The core idea: As you iterate, store everything you've seen in a hash map. For each new element, check the map in O(1) instead of scanning the array again in O(n). This collapses O(nΒ²) brute force to O(n).

When to recognise it: "Find two elements that sum to target," "find the first duplicate," "group elements by property," "count frequencies."

Example: Two Sum (unsorted)

def two_sum(nums, target):
    seen = {}  # value β†’ index
    
    for i, num in enumerate(nums):
        complement = target - num
        
        if complement in seen:
            return [seen[complement], i]
        
        seen[num] = i
    
    return []

The insight: For each number, the question becomes "have I seen target - num before?" The map answers that in O(1).

Subarray Sum Equals K β€” a harder application

def subarray_sum(nums, k):
    count = 0
    prefix_sum = 0
    freq = {0: 1}  # prefix_sum β†’ how many times seen
    
    for num in nums:
        prefix_sum += num
        
        # If (prefix_sum - k) was seen before, those subarrays sum to k
        count += freq.get(prefix_sum - k, 0)
        freq[prefix_sum] = freq.get(prefix_sum, 0) + 1
    
    return count

Problems to practice

  • Group Anagrams
  • Top K Frequent Elements
  • Longest Consecutive Sequence
  • Valid Anagram

Pattern 5: BFS / DFS on Graphs and Trees

What it solves: Everything involving graphs (grids count!), trees, connected components, shortest paths, or cycle detection.

BFS (Breadth-First Search): Use when you need the shortest path or want to process nodes level by level.

DFS (Depth-First Search): Use when you need to explore all paths, detect cycles, do topological sort, or don't care about shortest distance.

BFS Template

from collections import deque

def bfs(graph, start):
    visited = set([start])
    queue = deque([start])
    
    while queue:
        node = queue.popleft()
        
        for neighbor in graph[node]:
            if neighbor not in visited:
                visited.add(neighbor)
                queue.append(neighbor)

DFS Template (recursive)

def dfs(graph, node, visited):
    visited.add(node)
    
    for neighbor in graph[node]:
        if neighbor not in visited:
            dfs(graph, neighbor, visited)

Grid problems β€” treat the grid as a graph

def num_islands(grid):
    if not grid:
        return 0
    
    count = 0
    rows, cols = len(grid), len(grid[0])
    
    def dfs(r, c):
        if r < 0 or r >= rows or c < 0 or c >= cols or grid[r][c] != '1':
            return
        grid[r][c] = '0'  # mark visited by changing to '0'
        dfs(r+1, c)
        dfs(r-1, c)
        dfs(r, c+1)
        dfs(r, c-1)
    
    for r in range(rows):
        for c in range(cols):
            if grid[r][c] == '1':
                dfs(r, c)
                count += 1
    
    return count

Problems to practice

  • Clone Graph
  • Course Schedule (BFS topological sort)
  • Pacific Atlantic Water Flow
  • Word Ladder (BFS)
  • Number of Islands, Rotting Oranges

How to Use These Patterns in an Interview

When you see a new problem, ask these questions in order:

  1. Is the input sorted or can I sort it? β†’ Two Pointers might work
  2. Am I looking for a contiguous subarray or substring? β†’ Sliding Window
  3. Is it a linked list with possible cycles? β†’ Fast & Slow
  4. Am I doing repeated lookups inside a loop? β†’ Hash Map
  5. Is it a tree, grid, or graph problem? β†’ BFS or DFS (BFS for shortest path, DFS for everything else)

Most Medium problems fit cleanly into one pattern. Hard problems combine two or more β€” for example, Sliding Window + Hash Map, or DFS + Dynamic Programming.

The Fastest Way to Get Good

Don't try to do 200 problems. Do 40 problems very deliberately:

  • 8 per pattern
  • After each problem, write down which pattern you used and why
  • When you're wrong about the pattern, understand why before moving on

That deliberate practice will do more than 200 mindless LeetCode attempts.

Next step: Open the Practice section and filter by each pattern. Start with Easy, then Medium. Use the AI Tutor when you're genuinely stuck β€” not before you've tried for 20 minutes.

Ready to practice what you just learned?

Apply these concepts with AI-powered tools built for CS students.