JavaScript 算法与数据结构

JavaScript 算法与数据结构

前端工程师进阶之路:掌握这些算法,让你的代码更高效


目录

  1. 时间空间复杂度
  2. 数组与字符串
  3. 链表
  4. 栈与队列
  5. 树与二叉树
  6. 哈希表
  7. 排序算法
  8. 搜索算法
  9. 动态规划
  10. 回溯与递归
  11. 前端实战场景
  12. [LeetCode 经典题目](#LeetCode 经典题目)
  13. 算法思维总结
  14. 附录:常用代码模板

一、复杂度分析

1.1 时间复杂度

javascript 复制代码
// O(1) - 常数时间
function getFirst(arr) {
  return arr[0];
}

// O(log n) - 对数时间
function binarySearch(arr, target) {
  let left = 0;
  let right = arr.length - 1;
  
  while (left <= right) {
    const mid = Math.floor((left + right) / 2);
    if (arr[mid] === target) return mid;
    if (arr[mid] < target) left = mid + 1;
    else right = mid - 1;
  }
  return -1;
}

// O(n) - 线性时间
function findMax(arr) {
  let max = arr[0];
  for (let i = 1; i < arr.length; i++) {
    if (arr[i] > max) max = arr[i];
  }
  return max;
}

// O(n log n) - 线性对数时间(归并排序)
function mergeSort(arr) {
  if (arr.length <= 1) return arr;
  const mid = Math.floor(arr.length / 2);
  const left = mergeSort(arr.slice(0, mid));
  const right = mergeSort(arr.slice(mid));
  return merge(left, right);
}

function merge(left, right) {
  const result = [];
  let i = 0, j = 0;
  while (i < left.length && j < right.length) {
    if (left[i] <= right[j]) result.push(left[i++]);
    else result.push(right[j++]);
  }
  return [...result, ...left.slice(i), ...right.slice(j)];
}

// O(n^2) - 平方时间(冒泡排序)
function bubbleSort(arr) {
  const n = arr.length;
  for (let i = 0; i < n - 1; i++) {
    for (let j = 0; j < n - 1 - i; j++) {
      if (arr[j] > arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
      }
    }
  }
  return arr;
}

// O(2^n) - 指数时间(斐波那契递归)
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

1.2 空间复杂度

javascript 复制代码
// O(1) 空间 - 原地操作
function reverseInPlace(arr) {
  let left = 0, right = arr.length - 1;
  while (left < right) {
    [arr[left], arr[right]] = [arr[right], arr[left]];
    left++;
    right--;
  }
  return arr;
}

// O(n) 空间 - 需要额外数组
function copyArray(arr) {
  return [...arr];
}

// O(n) 空间 - 递归调用栈
function factorial(n) {
  if (n <= 1) return 1;
  return n * factorial(n - 1);
}

1.3 复杂度对比表

复杂度 名称 示例
O(1) 常数 数组取值、哈希表查找
O(log n) 对数 二分查找
O(n) 线性 遍历数组
O(n log n) 线性对数 归并排序、快速排序
O(n^2) 平方 冒泡排序、嵌套循环
O(2^n) 指数 子集生成、递归斐波那契
O(n!) 阶乘 全排列

二、数组与字符串

2.1 双指针技巧

javascript 复制代码
// 对撞指针 - 两数之和 II(有序数组)
function twoSumSorted(numbers, target) {
  let left = 0, right = numbers.length - 1;
  while (left < right) {
    const sum = numbers[left] + numbers[right];
    if (sum === target) return [left + 1, right + 1];
    if (sum < target) left++;
    else right--;
  }
  return [];
}

// 快慢指针 - 删除有序数组中的重复项
function removeDuplicates(nums) {
  if (nums.length === 0) return 0;
  let slow = 1;
  for (let fast = 1; fast < nums.length; fast++) {
    if (nums[fast] !== nums[fast - 1]) {
      nums[slow] = nums[fast];
      slow++;
    }
  }
  return slow;
}

// 滑动窗口 - 最长子串
function lengthOfLongestSubstring(s) {
  const set = new Set();
  let left = 0, maxLen = 0;
  for (let right = 0; right < s.length; right++) {
    while (set.has(s[right])) {
      set.delete(s[left]);
      left++;
    }
    set.add(s[right]);
    maxLen = Math.max(maxLen, right - left + 1);
  }
  return maxLen;
}

2.2 前缀和与差分数组

javascript 复制代码
// 前缀和 - 区间求和
class PrefixSum {
  constructor(arr) {
    this.prefix = [0];
    for (let i = 0; i < arr.length; i++) {
      this.prefix[i + 1] = this.prefix[i] + arr[i];
    }
  }

  rangeSum(left, right) {
    return this.prefix[right + 1] - this.prefix[left];
  }
}

// 差分数组 - 区间修改
class DiffArray {
  constructor(arr) {
    this.diff = new Array(arr.length).fill(0);
    this.diff[0] = arr[0];
    for (let i = 1; i < arr.length; i++) {
      this.diff[i] = arr[i] - arr[i - 1];
    }
  }

  increment(left, right, val) {
    this.diff[left] += val;
    if (right + 1 < this.diff.length) {
      this.diff[right + 1] -= val;
    }
  }

  result() {
    const res = [this.diff[0]];
    for (let i = 1; i < this.diff.length; i++) {
      res[i] = res[i - 1] + this.diff[i];
    }
    return res;
  }
}

2.3 字符串经典算法

javascript 复制代码
// KMP 字符串匹配
function kmpSearch(text, pattern) {
  if (!pattern.length) return 0;
  const lps = buildLPS(pattern);
  let i = 0, j = 0;
  while (i < text.length) {
    if (text[i] === pattern[j]) {
      i++;
      j++;
      if (j === pattern.length) return i - j;
    } else {
      if (j > 0) j = lps[j - 1];
      else i++;
    }
  }
  return -1;
}

function buildLPS(pattern) {
  const lps = new Array(pattern.length).fill(0);
  let len = 0, i = 1;
  while (i < pattern.length) {
    if (pattern[i] === pattern[len]) {
      len++;
      lps[i] = len;
      i++;
    } else {
      if (len > 0) len = lps[len - 1];
      else { lps[i] = 0; i++; }
    }
  }
  return lps;
}

// Manacher 最长回文子串
function longestPalindrome(s) {
  const t = '#' + s.split('').join('#') + '#';
  const n = t.length;
  const p = new Array(n).fill(0);
  let center = 0, rightBound = 0;
  let maxCenter = 0, maxLen = 0;
  for (let i = 0; i < n; i++) {
    if (i < rightBound) {
      p[i] = Math.min(rightBound - i, p[2 * center - i]);
    }
    while (i - p[i] - 1 >= 0 && i + p[i] + 1 < n && t[i - p[i] - 1] === t[i + p[i] + 1]) {
      p[i]++;
    }
    if (i + p[i] > rightBound) {
      center = i;
      rightBound = i + p[i];
    }
    if (p[i] > maxLen) {
      maxLen = p[i];
      maxCenter = i;
    }
  }
  const start = (maxCenter - maxLen) / 2;
  return s.substring(start, start + maxLen);
}

三、链表

3.1 链表实现

javascript 复制代码
class ListNode {
  constructor(val, next = null) {
    this.val = val;
    this.next = next;
  }
}

class LinkedList {
  constructor() {
    this.head = null;
    this.size = 0;
  }

  append(val) {
    const node = new ListNode(val);
    if (!this.head) {
      this.head = node;
    } else {
      let curr = this.head;
      while (curr.next) curr = curr.next;
      curr.next = node;
    }
    this.size++;
  }

  prepend(val) {
    this.head = new ListNode(val, this.head);
    this.size++;
  }

  delete(val) {
    if (!this.head) return;
    if (this.head.val === val) {
      this.head = this.head.next;
      this.size--;
      return;
    }
    let curr = this.head;
    while (curr.next) {
      if (curr.next.val === val) {
        curr.next = curr.next.next;
        this.size--;
        return;
      }
      curr = curr.next;
    }
  }

  toArray() {
    const result = [];
    let curr = this.head;
    while (curr) {
      result.push(curr.val);
      curr = curr.next;
    }
    return result;
  }
}

3.2 链表经典操作

javascript 复制代码
// 反转链表
function reverseList(head) {
  let prev = null, curr = head;
  while (curr) {
    const next = curr.next;
    curr.next = prev;
    prev = curr;
    curr = next;
  }
  return prev;
}

// 检测环(快慢指针)
function hasCycle(head) {
  let slow = head, fast = head;
  while (fast && fast.next) {
    slow = slow.next;
    fast = fast.next.next;
    if (slow === fast) return true;
  }
  return false;
}

// 找环的入口
function detectCycle(head) {
  let slow = head, fast = head;
  while (fast && fast.next) {
    slow = slow.next;
    fast = fast.next.next;
    if (slow === fast) {
      slow = head;
      while (slow !== fast) {
        slow = slow.next;
        fast = fast.next;
      }
      return slow;
    }
  }
  return null;
}

// 合并两个有序链表
function mergeTwoLists(l1, l2) {
  const dummy = new ListNode();
  let curr = dummy;
  while (l1 && l2) {
    if (l1.val <= l2.val) {
      curr.next = l1;
      l1 = l1.next;
    } else {
      curr.next = l2;
      l2 = l2.next;
    }
    curr = curr.next;
  }
  curr.next = l1 || l2;
  return dummy.next;
}

// 合并 K 个有序链表
function mergeKLists(lists) {
  if (!lists.length) return null;
  while (lists.length > 1) {
    const merged = [];
    for (let i = 0; i < lists.length; i += 2) {
      const l1 = lists[i];
      const l2 = i + 1 < lists.length ? lists[i + 1] : null;
      merged.push(mergeTwoLists(l1, l2));
    }
    lists = merged;
  }
  return lists[0];
}

// 链表中点
function findMiddle(head) {
  let slow = head, fast = head;
  while (fast && fast.next) {
    slow = slow.next;
    fast = fast.next.next;
  }
  return slow;
}

// 判断回文链表
function isPalindrome(head) {
  let slow = head, fast = head;
  while (fast && fast.next) {
    slow = slow.next;
    fast = fast.next.next;
  }
  let prev = null, curr = slow;
  while (curr) {
    const next = curr.next;
    curr.next = prev;
    prev = curr;
    curr = next;
  }
  let left = head, right = prev;
  while (right) {
    if (left.val !== right.val) return false;
    left = left.next;
    right = right.next;
  }
  return true;
}

四、栈与队列

4.1 栈的实现

javascript 复制代码
class Stack {
  constructor() {
    this.items = [];
  }

  push(val) { this.items.push(val); }
  pop() { return this.items.pop(); }
  peek() { return this.items[this.items.length - 1]; }
  isEmpty() { return this.items.length === 0; }
  size() { return this.items.length; }
}

4.2 队列与双端队列

javascript 复制代码
class Queue {
  constructor() { this.items = []; }
  enqueue(val) { this.items.push(val); }
  dequeue() { return this.items.shift(); }
  front() { return this.items[0]; }
  isEmpty() { return this.items.length === 0; }
}

class Deque {
  constructor() { this.items = []; }
  pushFront(val) { this.items.unshift(val); }
  pushBack(val) { this.items.push(val); }
  popFront() { return this.items.shift(); }
  popBack() { return this.items.pop(); }
  front() { return this.items[0]; }
  back() { return this.items[this.items.length - 1]; }
}

4.3 栈的经典应用

javascript 复制代码
// 有效的括号
function isValidParentheses(s) {
  const stack = [];
  const map = { ')': '(', ']': '[', '}': '{' };
  for (const char of s) {
    if (char === '(' || char === '[' || char === '{') {
      stack.push(char);
    } else {
      if (stack.pop() !== map[char]) return false;
    }
  }
  return stack.length === 0;
}

// 每日温度(单调栈)
function dailyTemperatures(temperatures) {
  const n = temperatures.length;
  const result = new Array(n).fill(0);
  const stack = [];
  for (let i = 0; i < n; i++) {
    while (stack.length && temperatures[i] > temperatures[stack[stack.length - 1]]) {
      const idx = stack.pop();
      result[idx] = i - idx;
    }
    stack.push(i);
  }
  return result;
}

// 柱状图最大矩形(单调栈)
function largestRectangleArea(heights) {
  const stack = [];
  let maxArea = 0;
  const arr = [...heights, 0];
  for (let i = 0; i < arr.length; i++) {
    while (stack.length && arr[i] < arr[stack[stack.length - 1]]) {
      const h = arr[stack.pop()];
      const w = stack.length ? i - stack[stack.length - 1] - 1 : i;
      maxArea = Math.max(maxArea, h * w);
    }
    stack.push(i);
  }
  return maxArea;
}

// 最小栈
class MinStack {
  constructor() {
    this.stack = [];
    this.minStack = [];
  }

  push(val) {
    this.stack.push(val);
    this.minStack.push(
      this.minStack.length ? Math.min(val, this.minStack[this.minStack.length - 1]) : val
    );
  }

  pop() { this.stack.pop(); this.minStack.pop(); }
  top() { return this.stack[this.stack.length - 1]; }
  getMin() { return this.minStack[this.minStack.length - 1]; }
}

// 表达式求值
function evalRPN(tokens) {
  const stack = [];
  for (const token of tokens) {
    if (['+', '-', '*', '/'].includes(token)) {
      const b = stack.pop();
      const a = stack.pop();
      switch (token) {
        case '+': stack.push(a + b); break;
        case '-': stack.push(a - b); break;
        case '*': stack.push(a * b); break;
        case '/': stack.push(Math.trunc(a / b)); break;
      }
    } else {
      stack.push(Number(token));
    }
  }
  return stack[0];
}

4.4 用栈实现队列

javascript 复制代码
class QueueByStacks {
  constructor() {
    this.inStack = [];
    this.outStack = [];
  }

  push(val) { this.inStack.push(val); }

  pop() {
    this._transfer();
    return this.outStack.pop();
  }

  peek() {
    this._transfer();
    return this.outStack[this.outStack.length - 1];
  }

  _transfer() {
    if (!this.outStack.length) {
      while (this.inStack.length) {
        this.outStack.push(this.inStack.pop());
      }
    }
  }
}

五、树与二叉树

5.1 二叉树基础

javascript 复制代码
class TreeNode {
  constructor(val, left = null, right = null) {
    this.val = val;
    this.left = left;
    this.right = right;
  }
}

function createTree(arr) {
  if (!arr.length) return null;
  const root = new TreeNode(arr[0]);
  const queue = [root];
  let i = 1;
  while (queue.length && i < arr.length) {
    const node = queue.shift();
    if (i < arr.length && arr[i] !== null) {
      node.left = new TreeNode(arr[i]);
      queue.push(node.left);
    }
    i++;
    if (i < arr.length && arr[i] !== null) {
      node.right = new TreeNode(arr[i]);
      queue.push(node.right);
    }
    i++;
  }
  return root;
}

5.2 遍历算法

javascript 复制代码
// 前序遍历(递归)
function preorderTraversal(root) {
  if (!root) return [];
  return [root.val, ...preorderTraversal(root.left), ...preorderTraversal(root.right)];
}

// 前序遍历(迭代)
function preorderIterative(root) {
  const result = [];
  const stack = [root];
  while (stack.length) {
    const node = stack.pop();
    if (!node) continue;
    result.push(node.val);
    stack.push(node.right);
    stack.push(node.left);
  }
  return result;
}

// 中序遍历(递归)
function inorderTraversal(root) {
  if (!root) return [];
  return [...inorderTraversal(root.left), root.val, ...inorderTraversal(root.right)];
}

// 中序遍历(迭代)
function inorderIterative(root) {
  const result = [];
  const stack = [];
  let curr = root;
  while (curr || stack.length) {
    while (curr) { stack.push(curr); curr = curr.left; }
    curr = stack.pop();
    result.push(curr.val);
    curr = curr.right;
  }
  return result;
}

// 后序遍历(迭代)
function postorderIterative(root) {
  const result = [];
  const stack = [root];
  while (stack.length) {
    const node = stack.pop();
    if (!node) continue;
    result.push(node.val);
    stack.push(node.left);
    stack.push(node.right);
  }
  return result.reverse();
}

// 层序遍历
function levelOrder(root) {
  if (!root) return [];
  const result = [];
  const queue = [root];
  while (queue.length) {
    const level = [];
    const size = queue.length;
    for (let i = 0; i < size; i++) {
      const node = queue.shift();
      level.push(node.val);
      if (node.left) queue.push(node.left);
      if (node.right) queue.push(node.right);
    }
    result.push(level);
  }
  return result;
}

5.3 二叉搜索树

javascript 复制代码
class BST {
  constructor() { this.root = null; }

  insert(val) { this.root = this._insert(this.root, val); }

  _insert(node, val) {
    if (!node) return new TreeNode(val);
    if (val < node.val) node.left = this._insert(node.left, val);
    else if (val > node.val) node.right = this._insert(node.right, val);
    return node;
  }

  search(val) {
    let curr = this.root;
    while (curr) {
      if (val === curr.val) return true;
      curr = val < curr.val ? curr.left : curr.right;
    }
    return false;
  }

  delete(val) { this.root = this._delete(this.root, val); }

  _delete(node, val) {
    if (!node) return null;
    if (val < node.val) node.left = this._delete(node.left, val);
    else if (val > node.val) node.right = this._delete(node.right, val);
    else {
      if (!node.left) return node.right;
      if (!node.right) return node.left;
      let minNode = node.right;
      while (minNode.left) minNode = minNode.left;
      node.val = minNode.val;
      node.right = this._delete(node.right, minNode.val);
    }
    return node;
  }
}

5.4 树的常用操作

javascript 复制代码
function maxDepth(root) {
  if (!root) return 0;
  return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}

function invertTree(root) {
  if (!root) return null;
  [root.left, root.right] = [root.right, root.left];
  invertTree(root.left);
  invertTree(root.right);
  return root;
}

function isSymmetric(root) {
  if (!root) return true;
  function isMirror(left, right) {
    if (!left && !right) return true;
    if (!left || !right) return false;
    return left.val === right.val
      && isMirror(left.left, right.right)
      && isMirror(left.right, right.left);
  }
  return isMirror(root.left, root.right);
}

function lowestCommonAncestor(root, p, q) {
  if (!root || root === p || root === q) return root;
  const left = lowestCommonAncestor(root.left, p, q);
  const right = lowestCommonAncestor(root.right, p, q);
  if (left && right) return root;
  return left || right;
}

function hasPathSum(root, targetSum) {
  if (!root) return false;
  if (!root.left && !root.right) return root.val === targetSum;
  return hasPathSum(root.left, targetSum - root.val)
    || hasPathSum(root.right, targetSum - root.val);
}

function rightSideView(root) {
  if (!root) return [];
  const result = [];
  const queue = [root];
  while (queue.length) {
    const size = queue.length;
    for (let i = 0; i < size; i++) {
      const node = queue.shift();
      if (i === size - 1) result.push(node.val);
      if (node.left) queue.push(node.left);
      if (node.right) queue.push(node.right);
    }
  }
  return result;
}

六、图

6.1 图的实现

javascript 复制代码
class Graph {
  constructor() { this.adjacencyList = new Map(); }

  addVertex(vertex) {
    if (!this.adjacencyList.has(vertex)) {
      this.adjacencyList.set(vertex, []);
    }
  }

  addEdge(v1, v2, weight = 1) {
    this.adjacencyList.get(v1).push({ node: v2, weight });
    this.adjacencyList.get(v2).push({ node: v1, weight });
  }

  addDirectedEdge(v1, v2, weight = 1) {
    this.adjacencyList.get(v1).push({ node: v2, weight });
  }
}

6.2 图的遍历

javascript 复制代码
function bfs(graph, start) {
  const visited = new Set([start]);
  const result = [];
  const queue = [start];
  while (queue.length) {
    const vertex = queue.shift();
    result.push(vertex);
    for (const { node } of graph.adjacencyList.get(vertex) || []) {
      if (!visited.has(node)) {
        visited.add(node);
        queue.push(node);
      }
    }
  }
  return result;
}

function dfs(graph, start) {
  const visited = new Set();
  const result = [];
  function dfsHelper(vertex) {
    visited.add(vertex);
    result.push(vertex);
    for (const { node } of graph.adjacencyList.get(vertex) || []) {
      if (!visited.has(node)) dfsHelper(node);
    }
  }
  dfsHelper(start);
  return result;
}

6.3 最短路径

javascript 复制代码
function dijkstra(graph, start) {
  const distances = new Map();
  const visited = new Set();
  const pq = [];

  for (const vertex of graph.adjacencyList.keys()) {
    distances.set(vertex, Infinity);
  }
  distances.set(start, 0);
  pq.push({ node: start, dist: 0 });

  while (pq.length) {
    pq.sort((a, b) => a.dist - b.dist);
    const { node: current } = pq.shift();
    if (visited.has(current)) continue;
    visited.add(current);

    for (const { node, weight } of graph.adjacencyList.get(current) || []) {
      const newDist = distances.get(current) + weight;
      if (newDist < distances.get(node)) {
        distances.set(node, newDist);
        pq.push({ node, dist: newDist });
      }
    }
  }
  return distances;
}

6.4 拓扑排序

javascript 复制代码
function topologicalSort(graph) {
  const inDegree = new Map();
  const result = [];

  for (const vertex of graph.adjacencyList.keys()) {
    inDegree.set(vertex, 0);
  }
  for (const [, neighbors] of graph.adjacencyList) {
    for (const { node } of neighbors) {
      inDegree.set(node, (inDegree.get(node) || 0) + 1);
    }
  }

  const queue = [];
  for (const [vertex, degree] of inDegree) {
    if (degree === 0) queue.push(vertex);
  }

  while (queue.length) {
    const vertex = queue.shift();
    result.push(vertex);
    for (const { node } of graph.adjacencyList.get(vertex) || []) {
      inDegree.set(node, inDegree.get(node) - 1);
      if (inDegree.get(node) === 0) queue.push(node);
    }
  }

  return result.length === graph.adjacencyList.size ? result : null;
}

6.5 并查集

javascript 复制代码
class UnionFind {
  constructor(n) {
    this.parent = Array.from({ length: n }, (_, i) => i);
    this.rank = new Array(n).fill(0);
    this.count = n;
  }

  find(x) {
    if (this.parent[x] !== x) {
      this.parent[x] = this.find(this.parent[x]);
    }
    return this.parent[x];
  }

  union(x, y) {
    const rootX = this.find(x);
    const rootY = this.find(y);
    if (rootX === rootY) return;
    if (this.rank[rootX] < this.rank[rootY]) {
      this.parent[rootX] = rootY;
    } else if (this.rank[rootX] > this.rank[rootY]) {
      this.parent[rootY] = rootX;
    } else {
      this.parent[rootY] = rootX;
      this.rank[rootX]++;
    }
    this.count--;
  }

  connected(x, y) { return this.find(x) === this.find(y); }
}

七、哈希表

7.1 哈希表实现

javascript 复制代码
class HashTable {
  constructor(size = 53) { this.keyMap = new Array(size); }

  _hash(key) {
    let total = 0;
    const PRIME = 31;
    for (let i = 0; i < Math.min(key.length, 100); i++) {
      total = (total * PRIME + (key.charCodeAt(i) - 96)) % this.keyMap.length;
    }
    return total;
  }

  set(key, value) {
    const index = this._hash(key);
    if (!this.keyMap[index]) this.keyMap[index] = [];
    for (const pair of this.keyMap[index]) {
      if (pair[0] === key) { pair[1] = value; return; }
    }
    this.keyMap[index].push([key, value]);
  }

  get(key) {
    const bucket = this.keyMap[this._hash(key)];
    if (bucket) {
      for (const [k, v] of bucket) { if (k === key) return v; }
    }
    return undefined;
  }
}

7.2 哈希表经典应用

javascript 复制代码
function twoSum(nums, target) {
  const map = new Map();
  for (let i = 0; i < nums.length; i++) {
    const complement = target - nums[i];
    if (map.has(complement)) return [map.get(complement), i];
    map.set(nums[i], i);
  }
  return [];
}

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

function longestConsecutive(nums) {
  const set = new Set(nums);
  let maxLen = 0;
  for (const num of set) {
    if (!set.has(num - 1)) {
      let curr = num, len = 1;
      while (set.has(curr + 1)) { curr++; len++; }
      maxLen = Math.max(maxLen, len);
    }
  }
  return maxLen;
}

class LRUCache {
  constructor(capacity) {
    this.capacity = capacity;
    this.cache = new Map();
  }

  get(key) {
    if (!this.cache.has(key)) return -1;
    const value = this.cache.get(key);
    this.cache.delete(key);
    this.cache.set(key, value);
    return value;
  }

  put(key, value) {
    if (this.cache.has(key)) {
      this.cache.delete(key);
    } else if (this.cache.size >= this.capacity) {
      this.cache.delete(this.cache.keys().next().value);
    }
    this.cache.set(key, value);
  }
}

八、排序算法

8.1 冒泡排序

javascript 复制代码
function bubbleSort(arr) {
  const n = arr.length;
  for (let i = 0; i < n - 1; i++) {
    let swapped = false;
    for (let j = 0; j < n - 1 - i; j++) {
      if (arr[j] > arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
        swapped = true;
      }
    }
    if (!swapped) break;
  }
  return arr;
}

8.2 选择排序

javascript 复制代码
function selectionSort(arr) {
  const n = arr.length;
  for (let i = 0; i < n - 1; i++) {
    let minIdx = i;
    for (let j = i + 1; j < n; j++) {
      if (arr[j] < arr[minIdx]) minIdx = j;
    }
    if (minIdx !== i) [arr[i], arr[minIdx]] = [arr[minIdx], arr[i]];
  }
  return arr;
}

8.3 插入排序

javascript 复制代码
function insertionSort(arr) {
  for (let i = 1; i < arr.length; i++) {
    const key = arr[i];
    let j = i - 1;
    while (j >= 0 && arr[j] > key) {
      arr[j + 1] = arr[j];
      j--;
    }
    arr[j + 1] = key;
  }
  return arr;
}

8.4 归并排序

javascript 复制代码
function mergeSort(arr) {
  if (arr.length <= 1) return arr;
  const mid = Math.floor(arr.length / 2);
  const left = mergeSort(arr.slice(0, mid));
  const right = mergeSort(arr.slice(mid));
  return merge(left, right);
}

function merge(left, right) {
  const result = [];
  let i = 0, j = 0;
  while (i < left.length && j < right.length) {
    if (left[i] <= right[j]) result.push(left[i++]);
    else result.push(right[j++]);
  }
  return [...result, ...left.slice(i), ...right.slice(j)];
}

8.5 快速排序

javascript 复制代码
function quickSort(arr, left = 0, right = arr.length - 1) {
  if (left < right) {
    const pivotIndex = partition(arr, left, right);
    quickSort(arr, left, pivotIndex - 1);
    quickSort(arr, pivotIndex + 1, right);
  }
  return arr;
}

function partition(arr, left, right) {
  const pivot = arr[right];
  let i = left - 1;
  for (let j = left; j < right; j++) {
    if (arr[j] < pivot) {
      i++;
      [arr[i], arr[j]] = [arr[j], arr[i]];
    }
  }
  [arr[i + 1], arr[right]] = [arr[right], arr[i + 1]];
  return i + 1;
}

8.6 堆排序

javascript 复制代码
function heapSort(arr) {
  const n = arr.length;
  for (let i = Math.floor(n / 2) - 1; i >= 0; i--) heapify(arr, n, i);
  for (let i = n - 1; i > 0; i--) {
    [arr[0], arr[i]] = [arr[i], arr[0]];
    heapify(arr, i, 0);
  }
  return arr;
}

function heapify(arr, n, i) {
  let largest = i;
  const left = 2 * i + 1;
  const right = 2 * i + 2;
  if (left < n && arr[left] > arr[largest]) largest = left;
  if (right < n && arr[right] > arr[largest]) largest = right;
  if (largest !== i) {
    [arr[i], arr[largest]] = [arr[largest], arr[i]];
    heapify(arr, n, largest);
  }
}

8.7 排序算法对比

算法 时间复杂度(平均) 空间复杂度 稳定性
冒泡排序 O(n^2) O(1) 稳定
选择排序 O(n^2) O(1) 不稳定
插入排序 O(n^2) O(1) 稳定
归并排序 O(n log n) O(n) 稳定
快速排序 O(n log n) O(log n) 不稳定
堆排序 O(n log n) O(1) 不稳定

九、搜索算法

9.1 二分查找

javascript 复制代码
function binarySearch(arr, target) {
  let left = 0, right = arr.length - 1;
  while (left <= right) {
    const mid = left + Math.floor((right - left) / 2);
    if (arr[mid] === target) return mid;
    if (arr[mid] < target) left = mid + 1;
    else right = mid - 1;
  }
  return -1;
}

// 搜索旋转排序数组
function searchRotated(nums, target) {
  let left = 0, right = nums.length - 1;
  while (left <= right) {
    const mid = left + Math.floor((right - left) / 2);
    if (nums[mid] === target) return mid;
    if (nums[left] <= nums[mid]) {
      if (target >= nums[left] && target < nums[mid]) right = mid - 1;
      else left = mid + 1;
    } else {
      if (target > nums[mid] && target <= nums[right]) left = mid + 1;
      else right = mid - 1;
    }
  }
  return -1;
}

9.2 DFS 与 BFS

javascript 复制代码
// 岛屿数量
function numIslands(grid) {
  if (!grid.length) return 0;
  let count = 0;
  const rows = grid.length, cols = grid[0].length;

  function dfs(r, c) {
    if (r < 0 || r >= rows || c < 0 || c >= cols || grid[r][c] !== '1') return;
    grid[r][c] = '0';
    dfs(r + 1, c); dfs(r - 1, c); dfs(r, c + 1); dfs(r, c - 1);
  }

  for (let r = 0; r < rows; r++) {
    for (let c = 0; c < cols; c++) {
      if (grid[r][c] === '1') { count++; dfs(r, c); }
    }
  }
  return count;
}

// BFS 最短路径(单词接龙)
function ladderLength(beginWord, endWord, wordList) {
  const wordSet = new Set(wordList);
  if (!wordSet.has(endWord)) return 0;
  const queue = [[beginWord, 1]];
  const visited = new Set([beginWord]);

  while (queue.length) {
    const [word, level] = queue.shift();
    for (let i = 0; i < word.length; i++) {
      for (let c = 97; c <= 122; c++) {
        const newWord = word.slice(0, i) + String.fromCharCode(c) + word.slice(i + 1);
        if (newWord === endWord) return level + 1;
        if (wordSet.has(newWord) && !visited.has(newWord)) {
          visited.add(newWord);
          queue.push([newWord, level + 1]);
        }
      }
    }
  }
  return 0;
}

十、动态规划

10.1 斐波那契与爬楼梯

javascript 复制代码
function climbStairs(n) {
  if (n <= 2) return n;
  let a = 1, b = 2;
  for (let i = 3; i <= n; i++) [a, b] = [b, a + b];
  return b;
}

function rob(nums) {
  if (!nums.length) return 0;
  if (nums.length === 1) return nums[0];
  let prev2 = 0, prev1 = 0;
  for (const num of nums) {
    [prev2, prev1] = [prev1, Math.max(prev1, prev2 + num)];
  }
  return prev1;
}

function rob2(nums) {
  if (nums.length === 1) return nums[0];
  return Math.max(rob(nums.slice(0, -1)), rob(nums.slice(1)));
}

10.2 背包问题

javascript 复制代码
function knapsack01(weights, values, capacity) {
  const n = weights.length;
  const dp = new Array(capacity + 1).fill(0);
  for (let i = 0; i < n; i++) {
    for (let w = capacity; w >= weights[i]; w--) {
      dp[w] = Math.max(dp[w], dp[w - weights[i]] + values[i]);
    }
  }
  return dp[capacity];
}

function coinChange(coins, amount) {
  const dp = new Array(amount + 1).fill(Infinity);
  dp[0] = 0;
  for (const coin of coins) {
    for (let i = coin; i <= amount; i++) {
      dp[i] = Math.min(dp[i], dp[i - coin] + 1);
    }
  }
  return dp[amount] === Infinity ? -1 : dp[amount];
}

10.3 子序列问题

javascript 复制代码
function lengthOfLIS(nums) {
  const dp = new Array(nums.length).fill(1);
  for (let i = 1; i < nums.length; i++) {
    for (let j = 0; j < i; j++) {
      if (nums[j] < nums[i]) dp[i] = Math.max(dp[i], dp[j] + 1);
    }
  }
  return Math.max(...dp);
}

function longestCommonSubsequence(text1, text2) {
  const m = text1.length, n = text2.length;
  const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
  for (let i = 1; i <= m; i++) {
    for (let j = 1; j <= n; j++) {
      if (text1[i - 1] === text2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
      else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
    }
  }
  return dp[m][n];
}

function maxSubArray(nums) {
  let maxSum = nums[0], currentSum = nums[0];
  for (let i = 1; i < nums.length; i++) {
    currentSum = Math.max(nums[i], currentSum + nums[i]);
    maxSum = Math.max(maxSum, currentSum);
  }
  return maxSum;
}

十一、回溯与递归

11.1 全排列与组合

javascript 复制代码
function permute(nums) {
  const result = [];
  function backtrack(path, used) {
    if (path.length === nums.length) {
      result.push([...path]);
      return;
    }
    for (let i = 0; i < nums.length; i++) {
      if (used.has(i)) continue;
      used.add(i);
      path.push(nums[i]);
      backtrack(path, used);
      path.pop();
      used.delete(i);
    }
  }
  backtrack([], new Set());
  return result;
}

function subsets(nums) {
  const result = [];
  function backtrack(start, path) {
    result.push([...path]);
    for (let i = start; i < nums.length; i++) {
      path.push(nums[i]);
      backtrack(i + 1, path);
      path.pop();
    }
  }
  backtrack(0, []);
  return result;
}

11.2 经典回溯问题

javascript 复制代码
function solveNQueens(n) {
  const result = [];
  const board = Array.from({ length: n }, () => new Array(n).fill('.'));

  function isValid(row, col) {
    for (let i = 0; i < row; i++) {
      if (board[i][col] === 'Q') return false;
      if (col - (row - i) >= 0 && board[i][col - (row - i)] === 'Q') return false;
      if (col + (row - i) < n && board[i][col + (row - i)] === 'Q') return false;
    }
    return true;
  }

  function backtrack(row) {
    if (row === n) { result.push(board.map(r => r.join(''))); return; }
    for (let col = 0; col < n; col++) {
      if (!isValid(row, col)) continue;
      board[row][col] = 'Q';
      backtrack(row + 1);
      board[row][col] = '.';
    }
  }
  backtrack(0);
  return result;
}

function generateParenthesis(n) {
  const result = [];
  function backtrack(str, left, right) {
    if (str.length === 2 * n) { result.push(str); return; }
    if (left < n) backtrack(str + '(', left + 1, right);
    if (right < left) backtrack(str + ')', left, right + 1);
  }
  backtrack('', 0, 0);
  return result;
}

function exist(board, word) {
  const rows = board.length, cols = board[0].length;
  function dfs(r, c, index) {
    if (index === word.length) return true;
    if (r < 0 || r >= rows || c < 0 || c >= cols || board[r][c] !== word[index]) return false;
    const temp = board[r][c];
    board[r][c] = '#';
    const found = dfs(r + 1, c, index + 1) || dfs(r - 1, c, index + 1)
      || dfs(r, c + 1, index + 1) || dfs(r, c - 1, index + 1);
    board[r][c] = temp;
    return found;
  }
  for (let r = 0; r < rows; r++) {
    for (let c = 0; c < cols; c++) {
      if (dfs(r, c, 0)) return true;
    }
  }
  return false;
}

十二、前端实战场景

12.1 防抖与节流

javascript 复制代码
function debounce(fn, delay) {
  let timer = null;
  return function (...args) {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}

function throttle(fn, delay) {
  let lastTime = 0;
  return function (...args) {
    const now = Date.now();
    if (now - lastTime >= delay) {
      lastTime = now;
      fn.apply(this, args);
    }
  };
}

12.2 深拷贝

javascript 复制代码
function deepClone(obj, hash = new WeakMap()) {
  if (obj === null || typeof obj !== 'object') return obj;
  if (hash.has(obj)) return hash.get(obj);
  const clone = Array.isArray(obj) ? [] : {};
  hash.set(obj, clone);
  for (const key of Reflect.ownKeys(obj)) {
    clone[key] = deepClone(obj[key], hash);
  }
  return clone;
}

12.3 发布订阅模式

javascript 复制代码
class EventBus {
  constructor() { this.events = new Map(); }

  on(event, callback) {
    if (!this.events.has(event)) this.events.set(event, []);
    this.events.get(event).push(callback);
  }

  off(event, callback) {
    if (!this.events.has(event)) return;
    this.events.set(event, this.events.get(event).filter(cb => cb !== callback));
  }

  emit(event, ...args) {
    if (!this.events.has(event)) return;
    for (const cb of this.events.get(event)) cb(...args);
  }

  once(event, callback) {
    const wrapper = (...args) => { callback(...args); this.off(event, wrapper); };
    this.on(event, wrapper);
  }
}

12.4 Promise 并发控制

javascript 复制代码
async function asyncPool(limit, tasks) {
  const results = [];
  const executing = new Set();

  for (const task of tasks) {
    const p = Promise.resolve().then(() => task());
    results.push(p);
    executing.add(p);
    p.finally(() => executing.delete(p));
    if (executing.size >= limit) await Promise.race(executing);
  }

  return Promise.all(results);
}

12.5 数组扁平化与去重

javascript 复制代码
function flatten(arr, depth = Infinity) {
  return arr.reduce((acc, val) =>
    Array.isArray(val) && depth > 0
      ? acc.concat(flatten(val, depth - 1))
      : acc.concat(val)
  , []);
}

function uniqueBy(arr, key) {
  const seen = new Set();
  return arr.filter(item => {
    const value = typeof key === 'function' ? key(item) : item[key];
    if (seen.has(value)) return false;
    seen.add(value);
    return true;
  });
}

12.6 数据结构转换

javascript 复制代码
function arrayToTree(arr) {
  if (!arr.length) return null;
  const root = { val: arr[0], left: null, right: null };
  const queue = [root];
  let i = 1;
  while (queue.length && i < arr.length) {
    const node = queue.shift();
    if (i < arr.length && arr[i] !== null) {
      node.left = { val: arr[i], left: null, right: null };
      queue.push(node.left);
    }
    i++;
    if (i < arr.length && arr[i] !== null) {
      node.right = { val: arr[i], left: null, right: null };
      queue.push(node.right);
    }
    i++;
  }
  return root;
}

function buildCommentTree(comments) {
  const map = new Map();
  const result = [];
  comments.forEach(c => map.set(c.id, { ...c, children: [] }));
  comments.forEach(c => {
    const node = map.get(c.id);
    if (c.parentId) {
      const parent = map.get(c.parentId);
      if (parent) parent.children.push(node);
    } else {
      result.push(node);
    }
  });
  return result;
}

12.7 函数组合与柯里化

javascript 复制代码
function pipe(...fns) {
  return initial => fns.reduce((acc, fn) => fn(acc), initial);
}

function compose(...fns) {
  return initial => fns.reduceRight((acc, fn) => fn(acc), initial);
}

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) return fn.apply(this, args);
    return (...args2) => curried.apply(this, args.concat(args2));
  };
}

十三、LeetCode 经典题目

13.1 简单难度

javascript 复制代码
function twoSum(nums, target) {
  const map = new Map();
  for (let i = 0; i < nums.length; i++) {
    const complement = target - nums[i];
    if (map.has(complement)) return [map.get(complement), i];
    map.set(nums[i], i);
  }
  return [];
}

function isPalindrome(x) {
  if (x < 0) return false;
  const str = x.toString();
  return str === str.split('').reverse().join('');
}

function mergeTwoLists(l1, l2) {
  const dummy = new ListNode();
  let curr = dummy;
  while (l1 && l2) {
    if (l1.val <= l2.val) { curr.next = l1; l1 = l1.next; }
    else { curr.next = l2; l2 = l2.next; }
    curr = curr.next;
  }
  curr.next = l1 || l2;
  return dummy.next;
}

function maxSubArray(nums) {
  let maxSum = nums[0], currentSum = nums[0];
  for (let i = 1; i < nums.length; i++) {
    currentSum = Math.max(nums[i], currentSum + nums[i]);
    maxSum = Math.max(maxSum, currentSum);
  }
  return maxSum;
}

function climbStairs(n) {
  if (n <= 2) return n;
  let a = 1, b = 2;
  for (let i = 3; i <= n; i++) [a, b] = [b, a + b];
  return b;
}

13.2 中等难度

javascript 复制代码
function threeSum(nums) {
  const result = [];
  nums.sort((a, b) => a - b);
  for (let i = 0; i < nums.length - 2; i++) {
    if (i > 0 && nums[i] === nums[i - 1]) continue;
    let left = i + 1, right = nums.length - 1;
    while (left < right) {
      const sum = nums[i] + nums[left] + nums[right];
      if (sum === 0) {
        result.push([nums[i], nums[left], nums[right]]);
        while (left < right && nums[left] === nums[left + 1]) left++;
        while (left < right && nums[right] === nums[right - 1]) right--;
        left++; right--;
      } else if (sum < 0) { left++; }
      else { right--; }
    }
  }
  return result;
}

function lengthOfLongestSubstring(s) {
  const set = new Set();
  let left = 0, maxLen = 0;
  for (let right = 0; right < s.length; right++) {
    while (set.has(s[right])) { set.delete(s[left]); left++; }
    set.add(s[right]);
    maxLen = Math.max(maxLen, right - left + 1);
  }
  return maxLen;
}

function generateParenthesis(n) {
  const result = [];
  function backtrack(str, left, right) {
    if (str.length === 2 * n) { result.push(str); return; }
    if (left < n) backtrack(str + '(', left + 1, right);
    if (right < left) backtrack(str + ')', left, right + 1);
  }
  backtrack('', 0, 0);
  return result;
}

function search(nums, target) {
  let left = 0, right = nums.length - 1;
  while (left <= right) {
    const mid = left + Math.floor((right - left) / 2);
    if (nums[mid] === target) return mid;
    if (nums[left] <= nums[mid]) {
      if (target >= nums[left] && target < nums[mid]) right = mid - 1;
      else left = mid + 1;
    } else {
      if (target > nums[mid] && target <= nums[right]) left = mid + 1;
      else right = mid - 1;
    }
  }
  return -1;
}

13.3 困难难度

javascript 复制代码
function mergeKLists(lists) {
  if (!lists.length) return null;
  while (lists.length > 1) {
    const merged = [];
    for (let i = 0; i < lists.length; i += 2) {
      merged.push(mergeTwoLists(lists[i], lists[i + 1] || null));
    }
    lists = merged;
  }
  return lists[0];
}

function trap(height) {
  let left = 0, right = height.length - 1;
  let leftMax = 0, rightMax = 0, water = 0;
  while (left < right) {
    if (height[left] < height[right]) {
      if (height[left] >= leftMax) leftMax = height[left];
      else water += leftMax - height[left];
      left++;
    } else {
      if (height[right] >= rightMax) rightMax = height[right];
      else water += rightMax - height[right];
      right--;
    }
  }
  return water;
}

function minDistance(word1, word2) {
  const m = word1.length, n = word2.length;
  const dp = Array.from({ length: m + 1 }, (_, i) =>
    Array.from({ length: n + 1 }, (_, j) => {
      if (i === 0) return j;
      if (j === 0) return i;
      return 0;
    })
  );
  for (let i = 1; i <= m; i++) {
    for (let j = 1; j <= n; j++) {
      if (word1[i - 1] === word2[j - 1]) dp[i][j] = dp[i - 1][j - 1];
      else dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
    }
  }
  return dp[m][n];
}

function longestValidParentheses(s) {
  const stack = [-1];
  let maxLen = 0;
  for (let i = 0; i < s.length; i++) {
    if (s[i] === '(') stack.push(i);
    else {
      stack.pop();
      if (!stack.length) stack.push(i);
      else maxLen = Math.max(maxLen, i - stack[stack.length - 1]);
    }
  }
  return maxLen;
}

十四、算法思维总结

14.1 五大算法思想

  1. 分治:将问题分解为子问题,分别求解后合并

    • 归并排序、快速排序、合并有序链表
  2. 动态规划:保存子问题结果,避免重复计算

    • 斐波那契、背包问题、最长公共子序列
  3. 贪心:每步选择局部最优解

    • 活动选择、哈夫曼编码
  4. 回溯:枚举所有可能路径,剪枝优化

    • 全排列、N皇后、括号生成
  5. 分支限界:BFS + 剪枝,寻找最优解

    • 最短路径、数独

14.2 常见模式速查

模式 适用场景 关键技巧
双指针 有序数组、链表 对撞指针、快慢指针
滑动窗口 子串、子数组 扩张 + 收缩
哈希表 快速查找、计数 空间换时间
递归/回溯 组合、排列 选与不选、状态恢复
动态规划 最优解、计数 状态定义、转移方程
单调栈 下一个更大元素 递减栈
优先队列 TOP-K、流式数据 最小堆/最大堆
位运算 状态压缩 与、或、异或

14.3 复杂度速查

数据结构 操作 时间复杂度
数组 访问 O(1)
数组 搜索 O(n)
数组 插入/删除 O(n)
链表 访问 O(n)
链表 插入/删除 O(1)
栈/队列 增删 O(1)
哈希表 增删改查 O(1)
二叉搜索树 增删改查 O(log n)
堆顶/插入 O(1) / O(log n)
图(BFS/DFS) 遍历 O(V + E)

14.4 面试高频 Top 20

  1. 两数之和 🔥🔥🔥🔥🔥
  2. 三数之和 🔥🔥🔥🔥🔥
  3. 滑动窗口最大值 🔥🔥🔥🔥
  4. 合并两个有序链表 🔥🔥🔥🔥
  5. 反转链表 🔥🔥🔥🔥🔥
  6. 环形链表 🔥🔥🔥🔥
  7. 全排列 🔥🔥🔥🔥
  8. 子集 🔥🔥🔥🔥
  9. 括号生成 🔥🔥🔥🔥
  10. 最长递增子序列 🔥🔥🔥🔥🔥
  11. 岛屿数量 🔥🔥🔥🔥
  12. 接雨水 🔥🔥🔥🔥🔥
  13. 最小栈 🔥🔥🔥🔥
  14. 二叉树遍历 🔥🔥🔥🔥
  15. 二叉树最近公共祖先 🔥🔥🔥🔥
  16. 编辑距离 🔥🔥🔥🔥🔥
  17. 爬楼梯 🔥🔥🔥🔥🔥
  18. 最大子序和 🔥🔥🔥🔥🔥
  19. 打家劫舍 🔥🔥🔥🔥
  20. 背包问题 🔥🔥🔥🔥🔥

14.5 刷题路线建议

复制代码
入门阶段(1-2 周)
├── 数组、字符串基本操作
├── 链表基础(反转、合并、检测环)
├── 栈与队列基础应用
└── 二叉树遍历(前/中/后/层序)

进阶阶段(2-4 周)
├── 双指针、滑动窗口
├── 二分查找及变体
├── 哈希表高频题
└── DFS/BFS 网格搜索

高级阶段(4-6 周)
├── 动态规划(背包、子序列、路径)
├── 回溯(排列、组合、N皇后)
├── 贪心算法
└── 图论(最短路径、拓扑排序)

冲刺阶段(1-2 周)
├── LeetCode Hot 100
├── 剑指 Offer 全刷
└── 模拟面试限时训练

附录:常用代码模板

快速排序模板

javascript 复制代码
function quickSort(arr) {
  if (arr.length <= 1) return arr;
  const pivot = arr[Math.floor(arr.length / 2)];
  const left = arr.filter(x => x < pivot);
  const middle = arr.filter(x => x === pivot);
  const right = arr.filter(x => x > pivot);
  return [...quickSort(left), ...middle, ...quickSort(right)];
}

归并排序模板

javascript 复制代码
function mergeSort(arr) {
  if (arr.length <= 1) return arr;
  const mid = Math.floor(arr.length / 2);
  const left = mergeSort(arr.slice(0, mid));
  const right = mergeSort(arr.slice(mid));
  return merge(left, right);
}

function merge(left, right) {
  const result = [];
  while (left.length && right.length) {
    result.push(left[0] <= right[0] ? left.shift() : right.shift());
  }
  return [...result, ...left, ...right];
}

二分搜索模板

javascript 复制代码
function binarySearch(arr, target) {
  let left = 0, right = arr.length - 1;
  while (left <= right) {
    const mid = Math.floor((left + right) / 2);
    if (arr[mid] === target) return mid;
    if (arr[mid] < target) left = mid + 1;
    else right = mid - 1;
  }
  return -1;
}

DFS 模板

javascript 复制代码
function dfs(node, state) {
  if (!node) return;
  process(node);
  dfs(node.left, newState);
  dfs(node.right, newState);
}

BFS 模板

javascript 复制代码
function bfs(root) {
  if (!root) return [];
  const result = [];
  const queue = [root];
  while (queue.length) {
    const node = queue.shift();
    result.push(node.val);
    if (node.left) queue.push(node.left);
    if (node.right) queue.push(node.right);
  }
  return result;
}

回溯模板

javascript 复制代码
function backtrack(path, choices) {
  if (meetCondition(path)) {
    result.push([...path]);
    return;
  }
  for (const choice of choices) {
    path.push(choice);
    backtrack(path, nextChoices);
    path.pop();
  }
}

滑动窗口模板

javascript 复制代码
function slidingWindow(s) {
  const window = new Map();
  let left = 0, right = 0;
  while (right < s.length) {
    window.set(s[right], (window.get(s[right]) || 0) + 1);
    while (windowNeedsShrink(window)) {
      window.set(s[left], window.get(s[left]) - 1);
      if (window.get(s[left]) === 0) window.delete(s[left]);
      left++;
    }
    right++;
  }
}

并查集模板

javascript 复制代码
class UnionFind {
  constructor(n) {
    this.parent = Array.from({ length: n }, (_, i) => i);
    this.rank = new Array(n).fill(0);
  }

  find(x) {
    if (this.parent[x] !== x) this.parent[x] = this.find(this.parent[x]);
    return this.parent[x];
  }

  union(x, y) {
    const px = this.find(x), py = this.find(y);
    if (px === py) return;
    if (this.rank[px] < this.rank[py]) this.parent[px] = py;
    else if (this.rank[px] > this.rank[py]) this.parent[py] = px;
    else { this.parent[py] = px; this.rank[px]++; }
  }

  connected(x, y) { return this.find(x) === this.find(y); }
}

Trie 模板

javascript 复制代码
class TrieNode {
  constructor() {
    this.children = {};
    this.isEnd = false;
  }
}

class Trie {
  constructor() { this.root = new TrieNode(); }

  insert(word) {
    let node = this.root;
    for (const ch of word) {
      if (!node.children[ch]) node.children[ch] = new TrieNode();
      node = node.children[ch];
    }
    node.isEnd = true;
  }

  search(word) {
    const node = this._find(word);
    return node !== null && node.isEnd;
  }

  startsWith(prefix) { return this._find(prefix) !== null; }

  _find(str) {
    let node = this.root;
    for (const ch of str) {
      if (!node.children[ch]) return null;
      node = node.children[ch];
    }
    return node;
  }
}

💪 总结 :本文涵盖前端 JavaScript 算法与数据结构的 核心知识点 ,从基础到实战,包含 50+ 经典题目,帮助你提升编码能力,攻克面试难题!

相关推荐
前端毕业班4 小时前
uniapp web 灵活控制 style scoped
前端·javascript·vue.js
水木流年追梦5 小时前
大模型入门-大模型分布式训练2
开发语言·分布式·python·算法·正则表达式·prompt
张元清5 小时前
在 React 里写动画又不跟渲染周期较劲:useRafFn、useRafState、useFps、useDevicePixelRatio、useUpdate
前端·javascript·面试
sali-tec5 小时前
C# 基于OpenCv的视觉工作流-章78-KRT测量
图像处理·人工智能·数码相机·opencv·算法·计算机视觉
菜菜的顾清寒5 小时前
力扣HOT100(32)二叉树的中序遍历
数据结构·算法·leetcode
x2c5 小时前
数据结构:线性表中链表的建立和基本操作(C)
算法
DolphinDB5 小时前
基于 DolphinDB 搭建微服务的 SpringBoot 项目
后端·算法
珊瑚里的鱼6 小时前
【动态规划】第N个泰波那契数
算法·动态规划
ComputerInBook6 小时前
C++ 23 相比 C++ 20 新增之特征
开发语言·算法·c++23
吴可可1236 小时前
样条曲线转多段线技巧
算法·c#