返回

前端常见算法题

前端

本文将介绍前端面试中常见的一些算法题,并提供解决这些问题的思路和示例代码。本文适合初级到中级的前端工程师参考。文章中,我们将以 JavaScript 代码为例来解释算法,以便于前端工程师轻松理解和应用。

本文将涵盖以下算法题:

  • 查找算法: 二分查找、哈希表查找
  • 排序算法: 冒泡排序、快速排序、归并排序
  • 搜索算法: 深度优先搜索、广度优先搜索
  • 动态规划: 最长公共子序列、最短路径
  • 贪心算法: 最小生成树、背包问题

以下是这些算法题的详细解释和示例代码:

查找算法:

  • 二分查找: 二分查找是一种快速查找算法,适用于有序数组。它通过每次将搜索范围减半,快速缩小查找范围,直到找到目标元素或确定目标元素不存在。
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;
    } else if (arr[mid] < target) {
      left = mid + 1;
    } else {
      right = mid - 1;
    }
  }

  return -1;
}
  • 哈希表查找: 哈希表查找是一种快速查找算法,适用于任何类型的数据。它使用哈希函数将键映射到值,以便于快速查找。
function hashTableLookup(hashTable, key) {
  const hash = hashFunction(key);
  const bucket = hashTable[hash];
  for (const entry of bucket) {
    if (entry.key === key) {
      return entry.value;
    }
  }

  return null;
}

排序算法:

  • 冒泡排序: 冒泡排序是一种简单易懂的排序算法。它通过反复比较相邻元素,将较大的元素向后移动,直到数组完全有序。
function bubbleSort(arr) {
  for (let i = 0; i < arr.length - 1; i++) {
    for (let j = 0; j < arr.length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        const temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
    }
  }

  return arr;
}
  • 快速排序: 快速排序是一种快速高效的排序算法。它通过选择一个枢轴元素,将数组分为两部分,然后递归地对两部分进行排序。
function quickSort(arr) {
  if (arr.length <= 1) {
    return arr;
  }

  const pivot = arr[Math.floor(arr.length / 2)];
  const left = [];
  const right = [];

  for (let i = 0; i < arr.length; i++) {
    if (arr[i] < pivot) {
      left.push(arr[i]);
    } else if (arr[i] > pivot) {
      right.push(arr[i]);
    }
  }

  return quickSort(left).concat(pivot, quickSort(right));
}
  • 归并排序: 归并排序是一种稳定且高效的排序算法。它通过将数组分成两部分,然后递归地对两部分进行排序,最后合并两个有序部分得到最终有序数组。
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 merged = [];
  let leftIndex = 0;
  let rightIndex = 0;

  while (leftIndex < left.length && rightIndex < right.length) {
    if (left[leftIndex] < right[rightIndex]) {
      merged.push(left[leftIndex]);
      leftIndex++;
    } else {
      merged.push(right[rightIndex]);
      rightIndex++;
    }
  }

  while (leftIndex < left.length) {
    merged.push(left[leftIndex]);
    leftIndex++;
  }

  while (rightIndex < right.length) {
    merged.push(right[rightIndex]);
    rightIndex++;
  }

  return merged;
}

搜索算法:

  • 深度优先搜索: 深度优先搜索是一种遍历图或树的算法。它通过沿着一条路径搜索到底,然后再回溯并搜索其他路径。
function depthFirstSearch(graph, start) {
  const visited = {};
  const stack = [start];

  while (stack.length > 0) {
    const current = stack.pop();
    if (!visited[current]) {
      visited[current] = true;
      console.log(current);

      for (const neighbor of graph[current]) {
        stack.push(neighbor);
      }
    }
  }
}
  • 广度优先搜索: 广度优先搜索是一种遍历图或树的算法。它通过逐层遍历节点,然后再搜索下一层节点。
function breadthFirstSearch(graph, start) {
  const visited = {};
  const queue = [start];

  while (queue.length > 0) {
    const current = queue.shift();
    if (!visited[current]) {
      visited[current] = true;
      console.log(current);

      for (const neighbor of graph[current]) {
        queue.push(neighbor);
      }
    }
  }
}

动态规划:

  • 最长公共子序列: 最长公共子序列是一种动态规划算法。它通过计算两个字符串的最长公共子序列的长度,来比较两个字符串的相似性。
function longestCommonSubsequence(str1, str2) {
  const dp = new Array(str1.length + 1).fill(0).map(() => new Array(str2.length + 1).fill(0));

  for (let i = 1; i <= str1.length; i++) {
    for (let j = 1; j <= str2.length; j++) {
      if (str1[i - 1] === str2[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[str1.length][str2.length];
}
  • 最短路径: 最短路径是一种动态规划算法。它通过计算从一个节点到另一个节点的最短路径的长度,来找到两个节点之间的最短路径。
function shortestPath(graph, start, end) {
  const distances = new Array(graph.length).fill(Infinity);
  distances[start] = 0;

  const queue = [start];
  while (queue.length > 0) {
    const current = queue.shift();
    for (const neighbor of graph[current]) {
      const distance = distances[current] + graph[current][neighbor];
      if (distance < distances[neighbor]) {
        distances[neighbor] = distance;
        queue.push(neighbor);
      }
    }
  }

  return distances[end];
}

贪心算法:

  • 最小生成树: 最小生成树是一种贪心算法。它通过选择权重最小的边,来构建一个连接所有节点的最小生成树。
function minimumSpanningTree(graph) {
  const edges = [];
  for (const node in graph) {
    for (const neighbor in graph[node]) {
      edges.push({
        node1: node,
        node2: neighbor,
        weight: graph[node][neighbor]
      });
    }