vishal maurya

DSA Patterns Roadmap for Beginners: 9 Patterns With Runnable Java

Overview

Part of the Interview Prep series. Dotted-underline words are glossary terms: hover for the meaning or open the Glossary. Track your progress on the Interview Prep tracker. Series index: Start here.

1. The mindset: patterns, not problems

You cannot memorise 2000 problems. You can learn about nine patterns and the trigger words that reveal them. The skill interviewers test is pattern recognition: reading a statement and thinking "sorted array and a pair, so two pointers".

Every pattern below follows the same four steps: trigger phrase, idea, Java code, complexity. If a word is unfamiliar (Big-O, heap, hash map), hover it or open the glossary in the Interview Prep section.

2. Pattern cheat sheet

#PatternTrigger words in the questionTypical complexity
1Two pointerssorted array, pair/triplet with sum, remove duplicates, palindromeO(n)
2Sliding windowlongest/shortest substring or subarray with a condition, "at most k"O(n)
3Hashing + prefix sumcount subarrays with sum k, two sum, frequency, anagramO(n)
4Binary searchsorted, "minimum value such that...", rotated arrayO(log n)
5Stackbrackets, next greater element, undo, expression evaluationO(n)
6Heaptop k, k-th largest, merge k lists, schedule by priorityO(n log k)
7BFS / DFSgrid, shortest path with equal weights, connected components, treeO(V + E)
8Dynamic programmingcount ways, min/max cost, "choose or skip", overlapping sub-problemsO(states)
9Backtrackingall combinations, permutations, subsets, N-queensexponential

3. All nine in one runnable file

import java.util.*;

/** One tiny, runnable example per DSA pattern. Read top to bottom. */
public class Patterns {

    // 1. TWO POINTERS: sorted array, find a pair with a given sum. O(n)
    static int[] twoSumSorted(int[] a, int target) {
        int l = 0, r = a.length - 1;
        while (l < r) {
            int s = a[l] + a[r];
            if (s == target) return new int[]{l, r};
            if (s < target) l++; else r--;
        }
        return new int[]{-1, -1};
    }

    // 2. SLIDING WINDOW: longest substring without repeating characters. O(n)
    static int longestUnique(String s) {
        Map<Character, Integer> last = new HashMap<>();
        int best = 0, left = 0;
        for (int right = 0; right < s.length(); right++) {
            Integer prev = last.put(s.charAt(right), right);
            if (prev != null && prev >= left) left = prev + 1;     // shrink window past the duplicate
            best = Math.max(best, right - left + 1);
        }
        return best;
    }

    // 3. HASHING + PREFIX SUM: number of subarrays whose sum equals k. O(n)
    static int subarraySum(int[] a, int k) {
        Map<Integer, Integer> seen = new HashMap<>();
        seen.put(0, 1);
        int sum = 0, count = 0;
        for (int x : a) {
            sum += x;
            count += seen.getOrDefault(sum - k, 0);
            seen.merge(sum, 1, Integer::sum);
        }
        return count;
    }

    // 4. BINARY SEARCH: first index with value >= target in a sorted array. O(log n)
    static int lowerBound(int[] a, int target) {
        int lo = 0, hi = a.length;
        while (lo < hi) {
            int mid = lo + (hi - lo) / 2;
            if (a[mid] < target) lo = mid + 1; else hi = mid;
        }
        return lo;
    }

    // 5. STACK: are the brackets balanced? O(n)
    static boolean balanced(String s) {
        Deque<Character> st = new ArrayDeque<>();
        for (char c : s.toCharArray()) {
            if ("([{".indexOf(c) >= 0) st.push(c);
            else {
                if (st.isEmpty()) return false;
                char o = st.pop();
                if ("([{".indexOf(o) != ")]}".indexOf(c)) return false;
            }
        }
        return st.isEmpty();
    }

    // 6. HEAP: k largest elements. O(n log k)
    static List<Integer> topK(int[] a, int k) {
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();
        for (int x : a) { minHeap.add(x); if (minHeap.size() > k) minHeap.poll(); }
        List<Integer> out = new ArrayList<>(minHeap);
        out.sort(Comparator.reverseOrder());
        return out;
    }

    // 7. BFS: shortest path in a grid of 0 (free) and 1 (wall). O(rows*cols)
    static int shortestPath(int[][] g) {
        int R = g.length, C = g[0].length;
        int[][] dist = new int[R][C];
        for (int[] row : dist) Arrays.fill(row, -1);
        Deque<int[]> q = new ArrayDeque<>();
        q.add(new int[]{0, 0}); dist[0][0] = 0;
        int[] dr = {1, -1, 0, 0}, dc = {0, 0, 1, -1};
        while (!q.isEmpty()) {
            int[] cur = q.poll();
            for (int d = 0; d < 4; d++) {
                int nr = cur[0] + dr[d], nc = cur[1] + dc[d];
                if (nr >= 0 && nc >= 0 && nr < R && nc < C && g[nr][nc] == 0 && dist[nr][nc] < 0) {
                    dist[nr][nc] = dist[cur[0]][cur[1]] + 1;
                    q.add(new int[]{nr, nc});
                }
            }
        }
        return dist[R - 1][C - 1];
    }

    // 8. DYNAMIC PROGRAMMING: fewest coins to make an amount (the exact ATM/vending change problem). O(amount * coins)
    static int minCoins(int[] coins, int amount) {
        int[] dp = new int[amount + 1];
        Arrays.fill(dp, Integer.MAX_VALUE);
        dp[0] = 0;
        for (int a = 1; a <= amount; a++)
            for (int c : coins)
                if (c <= a && dp[a - c] != Integer.MAX_VALUE) dp[a] = Math.min(dp[a], dp[a - c] + 1);
        return dp[amount] == Integer.MAX_VALUE ? -1 : dp[amount];
    }

    // 9. BACKTRACKING: all subsets. O(2^n)
    static void subsets(int[] a, int i, Deque<Integer> cur, List<List<Integer>> out) {
        if (i == a.length) { out.add(new ArrayList<>(cur)); return; }
        subsets(a, i + 1, cur, out);                       // skip a[i]
        cur.addLast(a[i]); subsets(a, i + 1, cur, out); cur.removeLast();   // take a[i], then undo
    }

    public static void main(String[] args) {
        System.out.println("two pointers   : " + Arrays.toString(twoSumSorted(new int[]{1, 3, 4, 6, 9}, 10)));
        System.out.println("sliding window : " + longestUnique("abcabcbb"));
        System.out.println("prefix + hash  : " + subarraySum(new int[]{1, 2, 3, -3, 3}, 3));
        System.out.println("binary search  : " + lowerBound(new int[]{1, 3, 5, 7, 9}, 6));
        System.out.println("stack          : " + balanced("{[()]}") + " " + balanced("([)]"));
        System.out.println("heap top-3     : " + topK(new int[]{5, 1, 9, 3, 7, 8}, 3));
        System.out.println("BFS grid       : " + shortestPath(new int[][]{{0, 0, 0}, {1, 1, 0}, {0, 0, 0}}));
        System.out.println("DP min coins   : " + minCoins(new int[]{1, 5, 10, 25}, 63) + " (greedy gives the same here)  "
                + minCoins(new int[]{1, 3, 4}, 6) + " (greedy would pick 4+1+1 = 3 coins; DP finds 3+3 = 2)");
        List<List<Integer>> out = new ArrayList<>();
        subsets(new int[]{1, 2, 3}, 0, new ArrayDeque<>(), out);
        System.out.println("backtracking   : " + out);
    }
}

Output:

two pointers   : [0, 4]
sliding window : 3
prefix + hash  : 5
binary search  : 3
stack          : true false
heap top-3     : [9, 8, 7]
BFS grid       : 4
DP min coins   : 6 (greedy gives the same here)  2 (greedy would pick 4+1+1 = 3 coins; DP finds 3+3 = 2)
backtracking   : [[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]]

4. How each pattern shows up in real design problems

  • Hash map / set: idempotency keys, active tickets, cache lookup.
  • Heap: simplify debts in Splitwise, rate-limiter expiry, schedulers.
  • Sorted structure and binary search: nearest free parking spot, elevator stops.
  • Stack/queue: undo, request queues, BFS.
  • Greedy vs DP: ATM and vending-machine change. Greedy works for 1, 5, 10, 25 but fails for coins 1, 3, 4 and amount 6 (see the output above). Always say this aloud.
  • Graph traversal: dependency order (topological sort), connected components (Union-Find).

5. Study order (the tracker on the Interview Prep page follows this)

  1. Arrays and strings, then hashing
  2. Two pointers, sliding window, prefix sums
  3. Stack and queue, linked list
  4. Binary search
  5. Recursion and backtracking
  6. Trees
  7. Heap
  8. Graphs: BFS, DFS, topological sort, Union-Find, Dijkstra
  9. Dynamic programming
  10. Greedy and intervals

For each topic solve 4 to 6 problems: two easy, two medium, one hard. After each problem write one line: "the trigger was ..., the pattern was ...".

6. How to practise without burning out

  • 45 minutes per problem. If stuck for 20, read the hint, not the full solution.
  • Re-solve a problem 3 days later without help. That second solve is what builds memory.
  • Say the complexity out loud every time.
  • Mix: one new topic problem and one revision problem a day.

7. Common beginner mistakes

  • Jumping to code before an example by hand.
  • Forgetting empty input, single element, duplicates, negative numbers.
  • Using O(n^2) when a hash map gives O(n).
  • Off-by-one in binary search: practise the template lo + (hi - lo) / 2 and the while (lo < hi) form until automatic.
  • Not saying the complexity.