互联网大厂高频大前端数据结构及算法面试题

文章目录

前端数据结构及算法篇

1. 如何实现一个高效的 LRU 缓存(Least Recently Used)?

答案解析
LRU 缓存需要快速访问最近使用的数据,并淘汰最久未使用的项。可以用 Map(保持插入顺序)结合键值对实现:

  • 时间复杂度:获取 O(1),插入/删除 O(1)。
  • 空间复杂度:O(n),n 为缓存容量。
  • 步骤
    1. 使用 Map 存储键值对。
    2. 获取时将键移到末尾(表示最近使用)。
    3. 插入时若超出容量,删除第一个元素(最久未使用)。

代码示例

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);
  }
}

应用场景

  • 浏览器缓存管理。
  • 前端数据请求缓存(如 API 结果)。

2. 如何判断一个链表是否有环?

答案解析
使用快慢指针(Floyd 判圈法):

  • 原理:快指针每次走 2 步,慢指针走 1 步,若有环两者必相遇。
  • 时间复杂度:O(n)。
  • 空间复杂度:O(1)。

代码示例

class ListNode {
   
  constructor(val) {
   
    this.val = val;
    this.next = null;
  }
}
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;
}

应用场景

  • 检测循环依赖(如模块加载)。
  • 浏览器事件循环调试。

3. 如何实现二叉树的层序遍历?

答案解析
层序遍历使用队列,按层从左到右访问节点:

  • 时间复杂度:O(n)。
  • 空间复杂度:O(w),w 为最大层宽。

代码示例

class TreeNode {
   
  constructor(val) {
   
    this.val = val;
    this.left = this.right = null;
  }
}
function levelOrder(root) {
   
  if (!root) return [];
  const queue = [root], result = [];
  while (queue.length) {
   
    const levelSize = queue.length;
    const level = [];
    for (let i = 0; i < levelSize; 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;
}

应用场景

  • DOM 树层级遍历。
  • 组件树渲染优化。

4. 如何实现一个高效的深拷贝函数?

答案解析
深拷贝需处理循环引用、特殊对象(如 Date、RegExp):

  • 方法:递归 + WeakMap 记录已拷贝对象。
  • 时间复杂度:O(n),n 为对象属性数。

代码示例

function deepClone(obj, map = new WeakMap()) {
   
  if (obj == null || typeof obj !== 'object') return obj;
  if (map.has(obj)) return map.get(obj);
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  const clone = Array.isArray(obj) ? [] : {
   };
  map.set(obj, clone);
  for (let key in obj) {
   
    if (obj.hasOwnProperty(key)) clone[key] = deepClone(obj[key], map);
  }
  return clone;
}

应用场景

  • Redux 状态拷贝。
  • 复杂对象的数据隔离。

5. 如何实现一个二叉搜索树(BST)的插入操作?

答案解析
BST 插入需保持左子树 < 根 < 右子树的性质:

  • 时间复杂度:O(h),h 为树高(最坏 O(n))。
  • 空间复杂度:O(h)(递归栈)。

代码示例

class BSTNode {
   
  constructor(val) {
   
    this.val = val;
    this.left = this.right = null;
  }
}
class BST {
   
  constructor() {
   
    this.root = null;
  }
  insert(val) {
   
    if (!this.root) {
   
      this.root = new BSTNode(val);
      return;
    }
    let current = this.root;
    while (true) {
   
      if (val < current.val) {
   
        if (!current.left) {
   
          current.left = new BSTNode(val);
          break;
        }
        current = current.left;
      } else {
   
        if (!current.right) {
   
          current.right = new BSTNode(val);
          break;
        }
        current = current.right;
      }
    }
  }
}

应用场景

  • 前端搜索建议排序。
  • 数据高效查找。

6. 如何实现快速排序算法?

答案解析
快速排序通过分区递归实现:

  • 步骤:选择基准(pivot),分区后递归排序。
  • 时间复杂度:平均 O(n log n),最坏 O(n²)。
  • 空间复杂度:O(log n)(递归栈)。

代码示例

function quickSort(arr, left = 0, right = arr.length - 1) {
   
  if (left >= right) return;
  const pivot = partition(arr, left, right);
  quickSort(arr, left, pivot - 1);
  quickSort(arr, pivot + 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;
}

应用场景

  • 大数据表格排序。
  • 前端列表渲染优化。

7. 如何检测数组中的重复元素?

答案解析
使用 Set 检测重复:

  • 时间复杂度:O(n)。
  • 空间复杂度:O(n)。

代码示例

function hasDuplicates(arr) {
   
  return arr.length !== new Set(arr).size;
}

应用场景

  • 用户输入校验(如唯一 ID)。
  • 数据去重处理。

8. 如何实现一个最小堆?

答案解析
最小堆是一种完全二叉树,父节点小于子节点:

  • 操作:插入时上浮,删除时下沉。
  • 时间复杂度:插入/删除 O(log n),构建 O(n)。

代码示例

class MinHeap {
   
  constructor() {
   
    this.heap = [];
  }
  insert(val) {
   
    this.heap.push(val);
    this.siftUp(this.heap.length - 1);
  }
  siftUp(index) {
   
    let parent = Math.floor((index - 1) / 2);
    while (index > 0 && this.heap[parent] > this.heap[index]) {
   
      [this.heap[parent], this.heap[index]] = [this.heap[index], this.heap[parent]];
      index = parent;
      parent = Math.floor((index - 1) / 2);
    }
  }
  extractMin() {
   
    if (!this.heap.length) return null;
    const min = this.heap[0];
    this.heap[0] = this.heap.pop();
    this.siftDown(0);
    return min;
  }
  siftDown(index) {
   
    const len = this.heap.length;
    while (true) {
   
      let min = index;
      const left = 2 * index + 1, right = 2 * index + 2;
      if (left < len && this.heap[left] < this.heap[min]) min = left;
      if (right < len && this.heap[right] < this.heap[min]) min = right;
      if (min === index) break;
      [this.heap[index], this.heap[min]] = [this.heap[min], this.heap[index]];
      index = min;
    }
  }
}

应用场景

  • 任务调度优先级队列。
  • 前端事件队列优化。

9. 如何实现一个 Trie(前缀树)?

答案解析
Trie 用于高效存储和查找字符串集合:

  • 时间复杂度:插入/查找 O(m),m 为字符串长度。
  • 空间复杂度:O(ALPHABET_SIZE * m * n),n 为字符串数。

代码示例

class TrieNode {
   
  constructor() {
   
    this.children = new Map();
    this.isEnd = false;
  }
}
class Trie {
   
  constructor() {
   
    this.root = new TrieNode();
  }
  insert(word) {
   
    let node = this.root;
    for (let char of word) {
   
      if (!node.children.has(char)) node.children.set(char, new TrieNode());
      node = node.children.get(char);
    }
    node.isEnd = true;
  }
  search(word) {
   
    let node = this.root;
    for (let char of word) {
   
      if (!node.children.has(char)) return false;
      node = node.children.get(char);
    }
    return node.isEnd;
  }
  startsWith(prefix) {
   
    let node = this.root;
    for (let char of prefix) {
   
      if (!node.children.has(char)) return false;
      node = node.children.get(char);
    }
    return true;
  }
}

应用场景

  • 搜索框自动补全。
  • 前端路由匹配。

10. 如何合并两个有序链表?

答案解析
通过比较节点值合并:

  • 时间复杂度:O(n + m),n、m 为链表长度。
  • 空间复杂度:O(1)(迭代)。

代码示例

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

应用场景

  • 合并排序后的数据流。
  • 前端列表合并渲染。

11. 如何实现一个拓扑排序?

答案解析
拓扑排序用于有向无环图(DAG),可用 DFS 或入度法:

  • 方法:入度法,使用队列处理入度为 0 的节点。
  • 时间复杂度:O(V + E)。

代码示例

function topologicalSort(graph) {
   
  const indegree = new Map(), queue = [], result = [];
  for (let node in graph) {
   
    indegree.set(node, 0);
  }
  for (let node in graph) {
   
    for (let neighbor of graph[node]) {
   
      indegree.set(neighbor, (indegree.get(neighbor) || 0) + 1);
    }
  }
  for (let [node, degree] of indegree) {
   
    if (degree === 0) queue.push(node);
  }
  while (queue.length) {
   
    const node = queue.shift();
    result.push(node);
    for (let neighbor of graph[node]) {
   
      indegree.set(neighbor, indegree.get(neighbor) - 1);
      if (indegree.get(neighbor) === 0) queue.push(neighbor);
    }
  }
  return result.length === Object.keys(graph).length ? result : [];
}

应用场景

  • 模块依赖解析。
  • 任务调度顺序。

12. 如何实现一个二分查找?

答案解析
二分查找适用于有序数组:

  • 时间复杂度:O(log n)。
  • 空间复杂度:O(1)。

代码示例

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;
}

应用场景

  • 前端搜索优化。
  • 数据分页查找。

13. 如何反转一个链表?

答案解析
通过迭代或递归反转指针:

  • 时间复杂度:O(n)。
  • 空间复杂度:O(1)(迭代)。

代码示例

function reverseList(head) {
   
  let prev = null, current = head;
  while (current) {
   
    const next = current.next;
    current.next = prev;
    prev = current;
    current = next;
  }
  return prev;
}

应用场景

  • 前端组件顺序调整。
  • 数据流反向处理。

14. 如何实现一个滑动窗口最大值算法?

答案解析
使用双端队列维护窗口内最大值:

  • 时间复杂度:O(n)。
  • 空间复杂度:O(k),k 为窗口大小。

代码示例

function maxSlidingWindow(nums, k) {
   
  const deque = [], result = [];
  for (let i = 0; i < nums.length; i++) {
   
    while (deque.length && deque[0] <= i - k) deque.shift();
    while (deque.length && nums[deque[deque.length - 1]] <= nums[i]) deque.pop();
    deque.push(i);
    if (i >= k - 1) result.push(nums[deque[0]]);
  }
  return result;
}

应用场景

  • 实时数据流分析。
  • 图表最大值展示。

15. 如何判断一个字符串是否是回文?

答案解析
双指针从两端向中间比较:

  • 时间复杂度:O(n)。
  • 空间复杂度:O(1)。

代码示例

function isPalindrome(s) {
   
  s = s.toLowerCase().replace(/[^a-z0-9]/g, '');
  let left = 0, right = s.length - 1;
  while (left < right) {
   
    if (s[left] !== s[right]) return false;
    left++;
    right--;
  }
  return true;
}

应用场景

  • 输入校验(如用户名)。
  • 前端表单验证。

16. 如何实现一个并查集(Union-Find)?

答案解析
并查集用于处理动态连通性:

  • 优化:路径压缩 + 按秩合并。
  • 时间复杂度:近似 O(1)(均摊)。

代码示例

class UnionFind {
   
  constructor(n) {
   
    this.parent = Array(n).fill().map((_, i) => i);
    this.rank = 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]++;
    }
  }
}

应用场景

  • 社交网络分组。
  • 前端组件连通性分析。

17. 如何实现一个字符串的最长公共前缀?

答案解析
逐个比较字符:

  • 时间复杂度:O(n * m),m 为最短字符串长度。
  • 空间复杂度:O(1)。

代码示例

function longestCommonPrefix(strs) {
   
  if (!strs.length) return '';
  let prefix = strs[0];
  for (let i = 1; i < strs.length; i++) {
   
    while (strs[i].indexOf(prefix) !== 0) {
   
      prefix = prefix.slice(0, -1);
      if (!prefix) return '';
    }
  }
  return prefix;
}

应用场景

  • 前端搜索建议分组。
  • 文件路径匹配。

18. 如何实现一个堆排序?

答案解析
堆排序基于最大堆:

  • 步骤:构建堆,逐步提取最大值。
  • 时间复杂度:O(n log n)。

代码示例

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, left = 2 * i + 1, 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);
  }
}

应用场景

  • 前端大数据排序。
  • 优先级任务处理。

19. 如何实现一个图的深度优先搜索(DFS)?

答案解析
DFS 使用递归或栈遍历图:

  • 时间复杂度:O(V + E)。
  • 空间复杂度:O(V)。

代码示例

function dfs(graph, start) {
   
  const visited = new Set(), result = [];
  function traverse(node) {
   
    visited.add(node);
    result.push(node);
    for (let neighbor of graph[node]) {
   
      if (!visited.has(neighbor)) traverse(neighbor);
    }
  }
  traverse(start);
  return result;
}

应用场景

  • DOM 树深度遍历。
  • 依赖关系解析。

20. 如何实现一个图的广度优先搜索(BFS)?

答案解析
BFS 使用队列按层遍历:

  • 时间复杂度:O(V + E)。
  • 空间复杂度:O(V)。

代码示例

function bfs(graph, start) {
   
  const visited = new Set(), queue = [start], result = [];
  visited.add(start);
  while (queue.length) {
   
    const node = queue.shift();
    result.push(node);
    for (let neighbor of graph[node]) {
   
      if (!visited.has(neighbor)) {
   
        visited.add(neighbor);
        queue.push(neighbor);
      }
    }
  }
  return result;
}

应用场景

  • 最短路径计算(如路由)。
  • 前端层级遍历。

21. 如何实现一个字符串的最长不重复子串?

答案解析
使用滑动窗口 + 哈希表:

  • 时间复杂度:O(n)。
  • 空间复杂度:O(min(m, n)),m 为字符集大小。

代码示例

function lengthOfLongestSubstring(s) {
   
  const map = new Map();
  let max = 0, left = 0;
  for (let right = 0; right < s.length; right++) {
   
    if (map.has(s[right])) left = Math.max(left, map.get(s[right]) + 1);
    map.set(s[right], right);
    max = Math.max(max, right - left + 1);
  }
  return max;
}

应用场景

  • 输入框唯一性校验。
  • 数据流分析。

22. 如何实现一个数组的全排列?

答案解析
使用回溯算法:

  • 时间复杂度:O(n!)。
  • 空间复杂度:O(n)。

代码示例

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[i]) continue;
      used[i] = true;
      path.push(nums[i]);
      backtrack(path, used);
      path.pop();
      used[i] = false;
    }
  }
  backtrack([], Array(nums.length).fill(false));
  return result;
}

应用场景

  • 前端组合生成(如菜单排列)。
  • 数据测试用例生成。

23. 如何实现一个接雨水问题?

答案解析
使用双指针或单调栈计算每列接水量:

  • 双指针法:左右指针计算水高。
  • 时间复杂度:O(n)。

代码示例

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

应用场景

  • 可视化数据处理。
  • 前端布局计算。

24. 如何实现一个岛屿数量计算?

答案解析
使用 DFS 标记连通区域:

  • 时间复杂度:O(m * n)。
  • 空间复杂度:O(m * n)(递归栈)。

代码示例

function numIslands(grid) {
   
  let count = 0;
  function dfs(i, j) {
   
    if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] === '0') return;
    grid[i][j] = '0';
    dfs(i - 1, j);
    dfs(i + 1, j);
    dfs(i, j - 1);
    dfs(i, j + 1);
  }
  for (let i = 0; i < grid.length; i++) {
   
    for (let j = 0; j < grid[0].length; j++) {
   
      if (grid[i][j] === '1') {
   
        count++;
        dfs(i, j);
      }
    }
  }
  return count;
}

应用场景

  • 前端图像分割。
  • 组件连通性分析。

25. 如何实现一个 LRU 缓存的链表版本?

答案解析
使用双向链表 + 哈希表:

  • 时间复杂度:O(1)。
  • 空间复杂度:O(n)。

代码示例

class DLinkedNode {
   
  constructor(key, value) {
   
    this.key = key;
    this.value = value;
    this.prev = this.next = null;
  }
}
class LRUCache {
   
  constructor(capacity) {
   
    this.capacity = capacity;
    this.map = new Map();
    this.head = new DLinkedNode(0, 0);
    this.tail = new DLinkedNode(0, 0);
    this.head.next = this.tail;
    this.tail.prev = this.head;
  }
  get(key) {
   
    if (!this.map.has(key)) return -1;
    const node = this.map.get(key);
    this.moveToHead(node);
    return node.value;
  }
  put(key, value) {
   
    if (this.map.has(key)) {
   
      const node = this.map.get(key);
      node.value = value;
      this.moveToHead(node);
    } else {
   
      const node = new DLinkedNode(key, value);
      this.map.set(key, node);
      this.addToHead(node);
      if (this.map.size > this.capacity) {
   
        const removed = this.removeTail();
        this.map.delete(removed.key);
      }
    }
  }
  moveToHead(node) {
   
    this.removeNode(node);
    this.addToHead(node);
  }
  addToHead(node) {
   
    node.prev = this.head;
    node.next = this.head.next;
    this.head.next.prev = node;
    this.head.next = node;
  }
  removeNode(node) {
   
    node.prev.next = node.next;
    node.next.prev = node.prev;
  }
  removeTail() {
   
    const node = this.tail.prev;
    this.removeNode(node);
    return node;
  }
}

应用场景

  • 高性能缓存设计。
  • 前端资源管理。

26. 如何实现一个最短路径算法(Dijkstra)?

答案解析
Dijkstra 使用优先队列计算单源最短路径:

  • 时间复杂度:O((V + E) log V)。
  • 空间复杂度:O(V)。

代码示例

function dijkstra(graph, start) {
   
  const distances = new Map(), pq = new MinHeap(), visited = new Set();
  for (let node in graph) distances.set(node, Infinity);
  distances.set(start, 0);
  pq.insert([0, start]);
  while (pq.heap.length) {
   
    const [dist, node] = pq.extractMin();
    if (visited.has(node)) continue;
    visited.add(node);
    for (let [neighbor, weight] of graph[node]) {
   
      const newDist = dist + weight;
      if (newDist < distances.get(neighbor)) {
   
        distances.set(neighbor, newDist);
        pq.insert([newDist, neighbor]);
      }
    }
  }
  return distances;
}

应用场景

  • 前端路由规划。
  • 网络请求优化。

27. 如何实现一个字符串匹配算法(KMP)?

答案解析
KMP 通过前缀表避免回溯:

  • 时间复杂度:O(n + m)。
  • 空间复杂度:O(m)。

代码示例

function kmpSearch(text, pattern) {
   
  const next = getNext(pattern);
  let i = 0, j = 0;
  while (i < text.length) {
   
    if (j === -1 || text[i] === pattern[j]) {
   
      i++;
      j++;
      if (j === pattern.length) return i - j;
    } else j = next[j];
  }
  return -1;
}
function getNext(pattern) {
   
  const next = [-1];
  let i = 0, j = -1;
  while (i < pattern.length) {
   
    if (j === -1 || pattern[i] === pattern[j]) {
   
      i++;
      j++;
      next[i] = j;
    } else j = next[j];
  }
  return next;
}

应用场景

  • 前端搜索高亮。
  • 文本匹配优化。

28. 如何实现一个数组的旋转?

答案解析
使用三次反转法:

  • 时间复杂度:O(n)。
  • 空间复杂度:O(1)。

代码示例

function rotate(arr, k) {
   
  k %= arr.length;
  reverse(arr, 0, arr.length - 1);
  reverse(arr, 0, k - 1);
  reverse(arr, k, arr.length - 1);
  return arr;
}
function reverse(arr, start, end) {
   
  while (start < end) {
   
    [arr[start], arr[end]] = [arr[end], arr[start]];
    start++;
    end--;
  }
}

应用场景

  • 前端轮播图切换。
  • 数据循环展示。

29. 如何实现一个二叉树的最近公共祖先(LCA)?

答案解析
递归查找路径交点:

  • 时间复杂度:O(h)。
  • 空间复杂度:O(h)。

代码示例

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;
}

应用场景

  • DOM 树节点关系分析。
  • 组件层级查找。

30. 如何实现一个数组的子集生成?

答案解析
使用回溯生成所有子集:

  • 时间复杂度:O(2^n)。
  • 空间复杂度:O(n)。

代码示例

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;
}

应用场景

  • 前端过滤选项组合。
  • 数据分析子集生成。

31. 如何实现一个最大子数组和?

答案解析
使用 Kadane 算法:

  • 时间复杂度:O(n)。
  • 空间复杂度:O(1)。

代码示例

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

应用场景

  • 数据趋势分析。
  • 前端图表计算。

32. 如何实现一个字符串的正则表达式匹配?

答案解析
使用动态规划处理通配符:

  • 时间复杂度:O(m * n)。
  • 空间复杂度:O(m * n)。

代码示例

function isMatch(s, p) {
   
  const m = s.length, n = p.length;
  const dp = Array(m + 1).fill().map(() => Array(n + 1).fill(false));
  dp[0][0] = true;
  for (let j = 1; j <= n; j++) {
   
    if (p[j - 1] === '*') dp[0][j] = dp[0][j - 2];
  }
  for (let i = 1; i <= m; i++) {
   
    for (let j = 1; j <= n; j++) {
   
      if (p[j - 1] === '.' || p[j - 1] === s[i - 1]) dp[i][j] = dp[i - 1][j - 1];
      else if (p[j - 1] === '*') {
   
        dp[i][j] = dp[i][j - 2] || (dp[i - 1][j] && (s[i - 1] === p[j - 2] || p[j - 2] === '.'));
      }
    }
  }
  return dp[m][n];
}

应用场景

  • 前端表单验证。
  • 搜索过滤逻辑。

33. 如何实现一个循环队列?

答案解析
使用数组模拟循环:

  • 时间复杂度:入队/出队 O(1)。
  • 空间复杂度:O(n)。

代码示例

class CircularQueue {
   
  constructor(capacity) {
   
    this.queue = new Array(capacity);
    this.capacity = capacity;
    this.front = 0;
    this.rear = 0;
    this.size = 0;
  }
  enqueue(value) {
   
    if (this.isFull()) return false;
    this.queue[this.rear] = value;
    this.rear = (this.rear + 1) % this.capacity;
    this.size++;
    return true;
  }
  dequeue() {
   
    if (this.isEmpty()) return null;
    const value = this.queue[this.front];
    this.front = (this.front + 1) % this.capacity;
    this.size--;
    return value;
  }
  isEmpty() {
   
    return this.size === 0;
  }
  isFull() {
   
    return this.size === this.capacity;
  }
}

应用场景

  • 前端任务缓冲。
  • 数据流循环处理。

34. 如何实现一个二叉树的中序遍历?

答案解析
中序遍历(左-根-右)使用递归或栈:

  • 时间复杂度:O(n)。
  • 空间复杂度:O(h)。

代码示例

function inorderTraversal(root) {
   
  const result = [], stack = [];
  let current = root;
  while (current || stack.length) {
   
    while (current) {
   
      stack.push(current);
      current = current.left;
    }
    current = stack.pop();
    result.push(current.val);
    current = current.right;
  }
  return result;
}

应用场景

  • BST 有序输出。
  • 前端树形组件渲染。

35. 如何实现一个字符串的最小窗口子串?

答案解析
使用滑动窗口 + 计数器:

  • 时间复杂度:O(n)。
  • 空间复杂度:O(k)。

代码示例

function minWindow(s, t) {
   
  const map = new Map();
  for (let char of t) map.set(char, (map.get(char) || 0) + 1);
  let left = 0, minLen = Infinity, minStart = 0, count = t.length;
  for (let right = 0; right < s.length; right++) {
   
    if (map.has(s[right])) {
   
      map.set(s[right], map.get(s[right]) - 1);
      if (map.get(s[right]) >= 0) count--;
    }
    while (count === 0) {
   
      if (right - left + 1 < minLen) {
   
        minLen = right - left + 1;
        minStart = left;
      }
      if (map.has(s[left])) {
   
        map.set(s[left], map.get(s[left]) + 1);
        if (map.get(s[left]) > 0) count++;
      }
      left++;
    }
  }
  return minLen === Infinity ? '' : s.slice(minStart, minStart + minLen);
}

应用场景

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天涯学馆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值