
DSA Patterns
🧩 DSA Patterns Cheatsheet
Most coding interview problems follow a handful of patterns. This cheatsheet covers the essential patterns with a template and example for each.
✅ Two pointers ✅ Sliding window ✅ Fast and slow pointers ✅ Binary search ✅ BFS and DFS ✅ Backtracking ✅ Dynamic programming ✅ Prefix sums and hashing
#dsa #algorithms #datastructures #interview #coding #patterns #webdev #tips
Most interview problems are variations of a small set of patterns. Recognizing the pattern is half the solution.
This cheatsheet provides a quick reference to the most common DSA patterns.
| Pattern | Use it when |
|---|---|
| Two pointers | Sorted array, pair finding, palindromes. |
| Sliding window | Contiguous subarray/substring with a condition. |
| Fast & slow pointers | Cycle detection, middle of a linked list. |
| Binary search | Sorted data, search space can be halved. |
| BFS | Shortest path in unweighted graphs, level order. |
| DFS | Exhaustive exploration, connectivity, paths. |
| Backtracking | Generate all combinations, permutations, subsets. |
| Dynamic programming | Overlapping subproblems, optimal substructure. |
| Prefix sum | Range sum queries, subarray sums. |
| Hashing | Frequency counting, lookups, grouping. |
| Monotonic stack | Next greater/smaller element problems. |
| Intervals | Overlapping ranges, merging, scheduling. |
Two pointers
Move two indices toward each other or in the same direction. Works best on sorted arrays.
// Find the pair of numbers that adds up to target sum
function pairSum(nums, target) {
let left = 0;
let right = nums.length - 1;
// While left is smaller than right
while (left < right) {
// sum is the "left" number plus the "right" number
const sum = nums[left] + nums[right];
// If sum equals to the target,
// return the left and right indices
if (sum === target) return [left, right];
// If sum is smaller than the target,
// increment "left" by 1
if (sum < target) left++;
// Other wise, decrement right by 1
else right--;
}
return [];
}Sliding window
Maintain a window over a contiguous range. Expand the right side, shrink the left when the condition breaks.
// Find the longest substring without repeating characters
function lengthOfLongest(s) {
const seen = new Set();
let left = 0;
let max = 0;
// Initialize the window, left = 0, right = 0
// For every iteration, expand the window by moving "right" right
for (let right = 0; right < s.length; right++) {
// While seen contains the "right" character
while (seen.has(s[right])) {
// Shrink the window by removing the "left" character
seen.delete(s[left]);
left++;
}
// If seen doesn't contain the "right" character
// Add the new "right" character to the window
seen.add(s[right]);
// Update the maximum window size
max = Math.max(max, right - left + 1);
}
return max;
}Fast and slow pointers
Move two pointers at different speeds. Classic for linked lists.
// Detect a cycle in a linked list
function hasCycle(head) {
let slow = head;
let fast = head;
// Fast moves 2 steps, slow moves 1 step
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
// If they meet, there is a cycle
if (slow === fast) return true;
}
// Fast reached the end, no cycle
return false;
}You may also use it to find the middle node. When fast reaches the end, slow is at the middle.
Binary search
Halve the search space each step. Requires sorted data or a monotonic condition.
// Find the target in a sorted array
function binarySearch(nums, target) {
let left = 0;
let right = nums.length - 1;
// Keep searching while "left" hasn't gone past "right"
while (left <= right) {
// Calculate the middle index
const mid = left + Math.floor((right - left) / 2);
// If the middle element is the target, return it
if (nums[mid] === target) return mid;
// If the middle is too small, move "left" to mid + 1
// to search the right half
if (nums[mid] < target) left = mid + 1;
// Otherwise, search the left half
else right = mid - 1;
}
return -1;
}Also works on "search the answer" problems: minimum capacity, koko eating bananas.
Breadth-First Search (BFS)
Explore level by level with a queue. Finds the shortest path in unweighted graphs.
// Traverse a tree level by level
function bfs(root) {
if (!root) return;
// Start with the root in the queue
const queue = [root];
// Process nodes until the queue is empty
while (queue.length > 0) {
// Dequeue the front node
const node = queue.shift();
console.log(node.value);
// Enqueue all children
for (const child of node.children ?? []) {
queue.push(child);
}
}
}Depth First Search (DFS)
Explore as deep as possible before backtracking. Uses recursion or a stack.
// Traverse a graph depth-first
function dfs(node, visited = new Set()) {
// Skip if already visited
if (!node || visited.has(node)) return;
// Mark as visited
visited.add(node);
console.log(node.value);
// Visit each neighbor recursively
for (const neighbor of node.neighbors ?? []) {
dfs(neighbor, visited);
}
}Backtracking
Build candidates incrementally and abandon paths that fail. The choose-explore-unchoose pattern.
// Generate all subsets of an array
function subsets(nums) {
const result = [];
function backtrack(start, current) {
// Save the current subset
result.push([...current]);
// Try adding each remaining element
for (let i = start; i < nums.length; i++) {
current.push(nums[i]); // choose
backtrack(i + 1, current); // explore
current.pop(); // unchoose
}
}
backtrack(0, []);
return result;
}Dynamic programming
Break a problem into overlapping subproblems and cache the results.
// Count the ways to climb n stairs (1 or 2 steps at a time)
function climbStairs(n) {
// Base cases: 1 way for 1 stair, 2 ways for 2 stairs
if (n <= 2) return n;
let prev = 1; // dp[i-2]
let curr = 2; // dp[i-1]
// Each step is reachable from the previous one or two
for (let i = 3; i <= n; i++) {
[prev, curr] = [curr, prev + curr];
}
return curr;
}The DP recipe.
- Define the state: what does
dp[i]represent? - Write the recurrence: how does
dp[i]relate to earlier states? - Set the base cases.
- Decide the iteration order.
Prefix sum
Precompute cumulative sums to answer range queries in O(1).
const nums = [1, 2, 3, 4, 5];
// Build the prefix sum array, starting with 0
const prefix = [0];
for (const n of nums) {
prefix.push(prefix[prefix.length - 1] + n);
}
// prefix = [0, 1, 3, 6, 10, 15]
// Sum of nums[i..j] inclusive = prefix[j+1] - prefix[i]
function rangeSum(i, j) {
return prefix[j + 1] - prefix[i];
}
rangeSum(1, 3); // 2 + 3 + 4 = 9Hashing
Trade space for time. Count frequencies, detect duplicates, group items.
// Find two numbers that add up to the target
function twoSum(nums, target) {
const seen = new Map();
for (let i = 0; i < nums.length; i++) {
// Calculate what number we need to reach the target
const complement = target - nums[i];
// If we have seen it before, return both indices
if (seen.has(complement)) return [seen.get(complement), i];
// Otherwise, store the current number and its index
seen.set(nums[i], i);
}
return [];
}Monotonic stack
Keep a stack in sorted order to find the next greater or smaller element.
// Find the next greater element for each position
function nextGreater(nums) {
const result = new Array(nums.length).fill(-1);
const stack = []; // indices with decreasing values
for (let i = 0; i < nums.length; i++) {
// Pop all smaller elements — their next greater is nums[i]
while (stack.length && nums[stack.at(-1)] < nums[i]) {
result[stack.pop()] = nums[i];
}
// Push the current index
stack.push(i);
}
// Remaining indices in the stack have no greater element
return result;
}Intervals
Sort by start time, then merge or compare adjacent intervals.
// Merge all overlapping intervals
function merge(intervals) {
// Sort by start time so overlaps are adjacent
intervals.sort((a, b) => a[0] - b[0]);
const merged = [intervals[0]];
for (let i = 1; i < intervals.length; i++) {
const last = merged[merged.length - 1];
// If the current interval overlaps with the last merged one
if (intervals[i][0] <= last[1]) {
// Extend the last interval's end
last[1] = Math.max(last[1], intervals[i][1]);
} else {
// No overlap, add as a new interval
merged.push(intervals[i]);
}
}
return merged;
}Full-Stack AI Developer Roadmap
From HTML & CSS to working with AI models, all in one structured roadmap.