JavaScript Coding Interview Patterns You Must Know

2025-08-14

If you learn a small set of patterns, most JavaScript interview questions stop feeling random. Below is a compact toolkit you can reuse across arrays, strings, graphs, and dynamic programming. Each pattern has a quick rule of thumb, a clean JS snippet, and when to use it.


1) Two Pointers

Use for: sorted arrays, partitioning, pair sums, moving from both ends.

// Return true if any pair sums to target in a sorted array
function hasPairSum(arr, target) {
  let i = 0, j = arr.length - 1;
  while (i < j) {
    const sum = arr[i] + arr[j];
    if (sum === target) return true;
    if (sum < target) i++;
    else j--;
  }
  return false;
}

Think: can advancing one pointer always get me closer to the goal


2) Sliding Window

Use for: longest substring without repeats, fixed or variable length subarrays.

// Length of longest substring without repeating characters
function lengthOfLongestSubstring(s) {
  const seen = new Map();
  let left = 0, best = 0;
  for (let right = 0; right < s.length; right++) {
    const ch = s[right];
    if (seen.has(ch) && seen.get(ch) >= left) left = seen.get(ch) + 1;
    seen.set(ch, right);
    best = Math.max(best, right - left + 1);
  }
  return best;
}

Rule: expand right to include, shrink left to restore validity


3) Binary Search on Array

Use for: find target, lower bound, upper bound in sorted arrays.

// First index >= target
function lowerBound(a, target) {
  let lo = 0, hi = a.length;
  while (lo < hi) {
    const mid = lo + ((hi - lo) >> 1);
    if (a[mid] < target) lo = mid + 1;
    else hi = mid;
  }
  return lo;
}

Gotcha: pick interval style and stick to it [lo, hi) or [lo, hi]


4) Binary Search on Answer

Use for: monotonic checks like minimum speed, capacity, days needed.

// Koko Eating Bananas style
function minSpeed(piles, h) {
  let lo = 1, hi = Math.max(...piles);
  const ok = k => piles.reduce((t, p) => t + Math.ceil(p / k), 0) <= h;
  while (lo < hi) {
    const mid = Math.floor((lo + hi) / 2);
    if (ok(mid)) hi = mid;
    else lo = mid + 1;
  }
  return lo;
}

Clue: if mid works then larger or smaller always works


5) Prefix Sum

Use for: fast range queries, subarray sums, counting with offsets.

// Count subarrays with sum == k
function subarraySum(nums, k) {
  const cnt = new Map([[0, 1]]);
  let sum = 0, ans = 0;
  for (const x of nums) {
    sum += x;
    ans += cnt.get(sum - k) || 0;
    cnt.set(sum, (cnt.get(sum) || 0) + 1);
  }
  return ans;
}

Tip: maps plus running sums unlock many O(n) solutions


6) Monotonic Stack

Use for: next greater element, largest rectangle in histogram, daily temperatures.

// Next greater element indices
function nextGreater(nums) {
  const res = Array(nums.length).fill(-1);
  const st = []; // decreasing stack of indices
  for (let i = 0; i < nums.length; i++) {
    while (st.length && nums[i] > nums[st[st.length - 1]]) {
      const j = st.pop();
      res[j] = i;
    }
    st.push(i);
  }
  return res;
}

Rule: maintain stack monotonicity so each index is pushed and popped once


7) Greedy with Sorting

Use for: intervals, assigning resources, jump game reachability.

// Minimum arrows to burst balloons
function findMinArrowShots(points) {
  points.sort((a, b) => a[1] - b[1]);
  let arrows = 0, end = -Infinity;
  for (const [s, e] of points) {
    if (s > end) { arrows++; end = e; }
  }
  return arrows;
}

Proof idea: exchange argument after sorting


8) Hash Map and Set Patterns

Use for: dedupe, frequency, anagrams, two sum unsorted.

// Group anagrams
function groupAnagrams(strs) {
  const map = new Map();
  for (const s of strs) {
    const key = s.split('').sort().join('');
    if (!map.has(key)) map.set(key, []);
    map.get(key).push(s);
  }
  return [...map.values()];
}

Trick: a stable key per equivalence class


9) BFS and DFS on Graphs

Use for: shortest path in unweighted graphs, islands, components.

// Number of islands with BFS
function numIslands(grid) {
  const m = grid.length, n = grid[0].length;
  const dirs = [[1,0],[-1,0],[0,1],[0,-1]];
  let count = 0;

  const bfs = (r, c) => {
    const q = [[r, c]];
    grid[r][c] = '0';
    while (q.length) {
      const [x, y] = q.shift();
      for (const [dx, dy] of dirs) {
        const nx = x + dx, ny = y + dy;
        if (nx>=0 && ny>=0 && nx<m && ny<n && grid[nx][ny]==='1') {
          grid[nx][ny] = '0';
          q.push([nx, ny]);
        }
      }
    }
  };

  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      if (grid[i][j] === '1') { count++; bfs(i, j); }
    }
  }
  return count;
}

Note: use a real queue for performance if the input is large


10) Topological Sort

Use for: course schedule, ordering with prerequisites, DAG scheduling.

function canFinish(n, edges) {
  const adj = Array.from({ length: n }, () => []);
  const indeg = Array(n).fill(0);
  for (const [u, v] of edges) { // u -> v means take u before v
    adj[u].push(v);
    indeg[v]++;
  }
  const q = [];
  for (let i = 0; i < n; i++) if (indeg[i] === 0) q.push(i);

  let seen = 0;
  for (let i = 0; i < q.length; i++) { // index as queue pointer
    const u = q[i]; seen++;
    for (const v of adj[u]) if (--indeg[v] === 0) q.push(v);
  }
  return seen === n;
}

Signal: directed edges with dependency language


11) Union Find

Use for: connectivity, detect cycles, count components.

class DSU {
  constructor(n) { this.p = Array.from({length:n}, (_, i) => i); this.r = Array(n).fill(0); }
  find(x) { return this.p[x] === x ? x : (this.p[x] = this.find(this.p[x])); }
  union(a, b) {
    a = this.find(a); b = this.find(b);
    if (a === b) return false;
    if (this.r[a] < this.r[b]) [a, b] = [b, a];
    this.p[b] = a;
    if (this.r[a] === this.r[b]) this.r[a]++;
    return true;
  }
}

Pattern: path compression and union by rank give near constant time


12) Heap with priority-queue polyfill

JavaScript lacks a built in heap. In interviews you can code a tiny binary heap or use a sorted array if n is small. Here is a minimal heap.

class MinHeap {
  constructor() { this.a = []; }
  size() { return this.a.length; }
  top() { return this.a[0]; }
  push(x) {
    const a = this.a; a.push(x);
    let i = a.length - 1;
    while (i > 0) {
      const p = (i - 1) >> 1;
      if (a[p] <= a[i]) break;
      [a[p], a[i]] = [a[i], a[p]];
      i = p;
    }
  }
  pop() {
    const a = this.a;
    if (a.length === 1) return a.pop();
    const v = a[0];
    a[0] = a.pop();
    let i = 0;
    while (true) {
      let l = i * 2 + 1, r = l + 1, s = i;
      if (l < a.length && a[l] < a[s]) s = l;
      if (r < a.length && a[r] < a[s]) s = r;
      if (s === i) break;
      [a[s], a[i]] = [a[i], a[s]];
      i = s;
    }
    return v;
  }
}

Example use: merge k sorted lists, Dijkstra, top k


13) Backtracking

Use for: subsets, permutations, combination sum, board search.

// Subsets
function subsets(nums) {
  const res = [], path = [];
  function dfs(i) {
    if (i === nums.length) { res.push(path.slice()); return; }
    dfs(i + 1);
    path.push(nums[i]);
    dfs(i + 1);
    path.pop();
  }
  dfs(0);
  return res;
}

Rule: choose, explore, unchoose. Add pruning when possible


14) Dynamic Programming

Use for: optimal substructure, overlapping subproblems.

// House Robber
function rob(nums) {
  let prev2 = 0, prev1 = 0;
  for (const x of nums) {
    const take = prev2 + x;
    const skip = prev1;
    const cur = Math.max(take, skip);
    prev2 = prev1; prev1 = cur;
  }
  return prev1;
}

Habit: state, transition, base cases, complexity


15) Bit Tricks

Use for: sets on small alphabets, parity masks, single number.

// Single number where every other number appears twice
const singleNumber = nums => nums.reduce((a, x) => a ^ x, 0);

Use carefully: only when it simplifies logic


16) Math and Counting

Use for: meeting rooms, intervals, sweep lines.

// Meeting Rooms II with sweep
function minMeetingRooms(intervals) {
  const starts = intervals.map(i => i[0]).sort((a,b)=>a-b);
  const ends = intervals.map(i => i[1]).sort((a,b)=>a-b);
  let rooms = 0, j = 0;
  for (let i = 0; i < starts.length; i++) {
    if (starts[i] < ends[j]) rooms++;
    else j++;
  }
  return rooms;
}

17) String Windows with Frequency Arrays

Faster than maps when the alphabet is fixed.

// Check s1 permutation in s2
function checkInclusion(s1, s2) {
  const need = Array(26).fill(0);
  for (const ch of s1) need[ch.charCodeAt(0) - 97]++;
  const win = Array(26).fill(0);
  let left = 0, matched = 0;
  for (let right = 0; right < s2.length; right++) {
    const r = s2.charCodeAt(right) - 97;
    if (++win[r] === need[r]) matched++;
    while (right - left + 1 > s1.length) {
      const l = s2.charCodeAt(left++) - 97;
      if (win[l] === need[l]) matched--;
      win[l]--;
    }
    if (matched === need.filter(x => x > 0).length) return true;
  }
  return false;
}

18) Clean Recursion With Memoization

Use for: top down DP, graphs with states.

// Climbing stairs with memo
function climbStairs(n, memo = new Map()) {
  if (n <= 2) return n;
  if (memo.has(n)) return memo.get(n);
  const v = climbStairs(n - 1, memo) + climbStairs(n - 2, memo);
  memo.set(n, v);
  return v;
}

Tip: memo keys should capture the full state


Interview checklist

  • Restate the problem and constraints in one minute
  • Match to a pattern from this list
  • State time and space up front
  • Walk a tiny example and call out invariants
  • Write code that reads top to bottom without surprises
  • Test one edge case out loud

Practice set that covers everything

  • Two pointers and window: Longest Substring Without Repeating Characters
  • Binary search on answer: Split Array Largest Sum
  • Prefix sum and map: Subarray Sum Equals K
  • Monotonic stack: Daily Temperatures
  • BFS and topo: Course Schedule
  • Union Find: Number of Connected Components
  • Greedy: Jump Game I and II
  • Heap: K Closest Points to Origin
  • Backtracking: Combination Sum
  • DP: House Robber and Edit Distance

Work through these and you will be ready for most JavaScript interviews.


If you want a quick way to see a solution outline and clean code while you practice, you can use a lightweight overlay that captures the prompt and shows you the steps to explain back with confidence. It helps you move faster when you are stuck.

Try StealthCoder when you want an instant explanation plus working code you can study: https://stealthcoder.app