LeetCode Patterns Cheatsheet (TypeScript)


1. Two Pointers

Когда: отсортированный массив, нужно O(n), ищем пару/подмассив.

// Пример: сумма двух чисел = target
function twoSum(nums: number[], target: number): number[] {
  let i = 0, j = nums.length - 1;
  while (i < j) {
    const sum = nums[i] + nums[j];
    if (sum === target) return [i, j];
    else if (sum < target) i++;
    else j--;
  }
  return [];
}

2. Sliding Window

Когда: подмассив/подстрока фиксированной или переменной длины, нужен максимум/минимум/условие.

// Пример: максимальная сумма подмассива длины k
function maxSum(nums: number[], k: number): number {
  let sum = nums.slice(0, k).reduce((a, b) => a + b, 0);
  let max = sum;
  for (let i = k; i < nums.length; i++) {
    sum += nums[i] - nums[i - k];
    max = Math.max(max, sum);
  }
  return max;
}

Когда: отсортированный массив, нужно O(log n).

function binarySearch(nums: number[], target: number): number {
  let lo = 0, hi = nums.length - 1;
  while (lo <= hi) {
    const mid = (lo + hi) >> 1;
    if (nums[mid] === target) return mid;
    else if (nums[mid] < target) lo = mid + 1;
    else hi = mid - 1;
  }
  return -1;
}

4. Prefix Sum

Когда: много запросов суммы диапазона [i, j].

function buildPrefix(nums: number[]): number[] {
  const prefix = [0];
  for (const n of nums) prefix.push(prefix.at(-1)! + n);
  return prefix;
}
// сумма [i, j] = prefix[j+1] - prefix[i]

5. HashMap / HashSet

Когда: нужно считать частоту, проверять наличие, находить дубликаты за O(1).

// Пример: два числа дают target (неотсортированный массив)
function twoSumHash(nums: number[], target: number): number[] {
  const map = new Map<number, number>();
  for (let i = 0; i < nums.length; i++) {
    const comp = target - nums[i];
    if (map.has(comp)) return [map.get(comp)!, i];
    map.set(nums[i], i);
  }
  return [];
}

6. Monotonic Stack

Когда: “следующий больший/меньший элемент”, диапазоны, температуры.

// Пример: следующий больший элемент
function nextGreater(nums: number[]): number[] {
  const result = new Array(nums.length).fill(-1);
  const stack: number[] = []; // хранит индексы
  for (let i = 0; i < nums.length; i++) {
    while (stack.length && nums[i] > nums[stack.at(-1)!]) {
      result[stack.pop()!] = nums[i];
    }
    stack.push(i);
  }
  return result;
}

7. BFS (обход в ширину)

Когда: кратчайший путь в графе/матрице, обход по уровням дерева.

function bfs(graph: Map<number, number[]>, start: number): number[] {
  const visited = new Set([start]);
  const queue = [start];
  const order: number[] = [];
  while (queue.length) {
    const node = queue.shift()!;
    order.push(node);
    for (const neighbor of graph.get(node) ?? []) {
      if (!visited.has(neighbor)) {
        visited.add(neighbor);
        queue.push(neighbor);
      }
    }
  }
  return order;
}

8. DFS (обход в глубину)

Когда: все пути, компоненты связности, комбинации/перестановки.

function dfs(graph: Map<number, number[]>, node: number, visited = new Set<number>()): void {
  visited.add(node);
  for (const neighbor of graph.get(node) ?? []) {
    if (!visited.has(neighbor)) dfs(graph, neighbor, visited);
  }
}

9. Backtracking

Когда: все комбинации/перестановки/подмножества с ограничениями.

// Пример: все подмножества
function subsets(nums: number[]): number[][] {
  const result: number[][] = [];
  function bt(start: number, current: number[]) {
    result.push([...current]);
    for (let i = start; i < nums.length; i++) {
      current.push(nums[i]);
      bt(i + 1, current);
      current.pop(); // откат
    }
  }
  bt(0, []);
  return result;
}

10. Dynamic Programming

Когда: оптимальное решение строится из подзадач, есть перекрывающиеся состояния.

// Пример: монеты (coin change)
function coinChange(coins: number[], amount: number): number {
  const dp = new Array(amount + 1).fill(Infinity);
  dp[0] = 0;
  for (let i = 1; i <= amount; i++) {
    for (const coin of coins) {
      if (coin <= i) dp[i] = Math.min(dp[i], dp[i - coin] + 1);
    }
  }
  return dp[amount] === Infinity ? -1 : dp[amount];
}

11. Heap / Priority Queue

Когда: k-й наибольший/наименьший элемент, слияние k отсортированных списков.
(В JS нет встроенного heap — используй библиотеку или реализуй минимальную.)

// Мини-heap вручную (min-heap через массив)
class MinHeap {
  private h: number[] = [];
  push(val: number) {
    this.h.push(val);
    this.h.sort((a, b) => a - b); // упрощённо; для O(log n) — sift up
  }
  pop(): number { return this.h.shift()!; }
  peek(): number { return this.h[0]; }
  size(): number { return this.h.length; }
}

12. Fast & Slow Pointers (Floyd’s)

Когда: цикл в связном списке, середина списка.

// Пример: есть ли цикл
function hasCycle(head: ListNode | null): boolean {
  let slow = head, fast = head;
  while (fast && fast.next) {
    slow = slow!.next;
    fast = fast.next.next;
    if (slow === fast) return true;
  }
  return false;
}

Когда что использовать — быстрая шпаргалка

Сигнал в задачеПаттерн
Отсортированный массив + O(n)Two Pointers
Подмассив/подстрока + max/minSliding Window
Отсортированный + O(log n)Binary Search
Сумма диапазоновPrefix Sum
Дубликаты, частота, O(1) поискHashMap/HashSet
Следующий больший/меньшийMonotonic Stack
Кратчайший путь, уровниBFS
Все пути, компонентыDFS
Все комбинации с откатомBacktracking
Оптимум из подзадачDynamic Programming
k-й элемент, топ-kHeap
Цикл в списке, серединаFast & Slow Pointers

← LeetCode

Примеры паттернов в заметках

leetcode

0 items under this folder.