前端JS面试高频算法题解析与实现

作者:青柠

时间:2026-10-21

浏览:287

本文总结了前端开发面试中常见的基础算法问题,涵盖回文判断、数组去重、字符统计、冒泡与快速排序、整数交换、斐波那契数列绘制、最大差值计算、随机字符串生成、DOM类名查找及二叉查找树实现。通过具体代码示例解析核心逻辑,帮助开发者掌握常用算法思路与优化技巧,提升面试应对能力。

文章目录

前端面试算法题概览

前言

掌握数据结构与算法知识,有助于工程师更清晰地理解和分析各类问题。当面对复杂场景时,扎实的基础积累能帮助构建更优的解决思路。以下列举了前端面试中频繁出现的几类典型算法问题。

回文判断与字符串处理

Q1 判断一个单词是否是回文?

回文(Palindrome)指正读和反读都相同的词汇或句子,形成首尾回环的效果,例如 'mamam redivider'。

面对此类题目,初学者常想到的方法是将字符串反转后与原串进行匹配。但这道题的核心考点在于对 reverse 方法的运用。关键在于将字符串转换为数组,从而获得更灵活的操作空间来处理字符串。


function checkPalindrom(str) { 
  return str == str.split('').reverse().join('');
}

数组去重与对象键值应用

Q2 去掉一组整型数组重复的值

例如输入:[1,13,24,11,11,14,1,2]

期望输出:[1,13,24,11,14,2]

需要去除数组中重复出现的元素 11 和 1。

此题在前端面试中较为常见,主要考察对 Object 对象的使用,特别是利用对象的 key(键)具有唯一性的特点来进行数据筛选。


/**
* unique an array 
**/
let unique = function(arr) { 
 let hashTable = {};
 let data = [];
 for(let i=0,l=arr.length;i<l;i++) {
  if(!hashTable[arr[i]]) {
   hashTable[arr[i]] = true;
   data.push(arr[i]);
  }
 }
 return data

}

module.exports = unique; 

字符统计与频次分析

Q3 统计一个字符串出现最多的字母

给定一段连续的英文字符串,目标是找出其中重复出现次数最多的字母。

输入示例:afjghdfraaaasdenas

输出示例:a

此前已涉及去重算法,本题则进一步要求统计字符的重复频次。


function findMaxDuplicateChar(str) { 
 if(str.length == 1) {
  return str;
 }
 let charObj = {};
 for(let i=0;i<str.length;i++) {
  if(!charObj[str.charAt(i)]) {
   charObj[str.charAt(i)] = 1;
  }else{
   charObj[str.charAt(i)] += 1;
  }
 }
 let maxChar = '',
   maxValue = 1;
 for(var k in charObj) {
  if(charObj[k] >= maxValue) {
   maxChar = k;
   maxValue = charObj[k];
  }
 }
 return maxChar;

}

module.exports = findMaxDuplicateChar; 

常见排序算法解析

Q4 排序算法

若面试中遇到算法题,通常允许自由选择实现方式,但必须熟练掌握其中几种基础算法。因此,冒泡排序作为一种基础且易于理解的算法,必须熟记于心。其原理是通过相邻元素的大小比较与位置交换,逐步将较小的元素移至前端。


function bubbleSort(arr) { 
  for(let i = 0,l=arr.length;i<l-1;i++) {
    for(let j = i+1;j<l;j++) { 
     if(arr[i]>arr[j]) {
        let tem = arr[i];
        arr[i] = arr[j];
        arr[j] = tem;
      }
    }
  }
  return arr;
}
module.exports = bubbleSort; 

除冒泡排序外,还有插入排序、快速排序、希尔排序等多种算法,各有优劣。虽无需掌握全部,但需熟悉几种典型算法。例如快速排序效率较高,其基本原理如图所示(来源:wiki):

前端面试算法题概览

快速排序选取一个基准元素,将小于基准的值放入左数组,大于基准的值放入右数组,随后对左右子数组递归执行相同操作,最终合并返回的数组即为有序结果。


function quickSort(arr) {

  if(arr.length<=1) {
    return arr;
  }

  let leftArr = [];
  let rightArr = [];
  let q = arr[0];
  for(let i = 1,l=arr.length; i<l; i++) {
    if(arr[i]>q) {
      rightArr.push(arr[i]);
    }else{
      leftArr.push(arr[i]);
    }
  }

  return [].concat(quickSort(leftArr),[q],quickSort(rightArr));
}

module.exports = quickSort; 

推荐一个通过动画演示算法执行过程的学习资源。

HTML5 Canvas Demo: Sorting Algorithms

整数交换与数学技巧

Q5 不借助临时变量,进行两个整数的交换

输入 a = 2, b = 4,期望输出 a = 4, b = 2

此题设计巧妙,旨在考察跳出常规思维的能力,通过数学运算实现变量置换。

主要利用加法和减法进行运算,例如 a = a + (b - a),其逻辑等价于最终 a = b。


function swap(a , b) { 
 b = b - a;
 a = a + b;
 b = a - b;
 return [a,b];
}

module.exports = swap; 

斐波那契数列与Canvas绘制

Q6 使用canvas 绘制一个有限度的斐波那契数列的曲线?

前端面试算法题概览 

数列长度限制为 9。

斐波那契数列(Fibonacci sequence),又称黄金分割数列,形式为:0、1、1、2、3、5、8、13、21、34……在数学层面,该数列主要考察递归调用的应用。通常定义如下:


fibo[i] = fibo[i-1]+fibo[i-2]; 

生成斐波那契数组的方法


function getFibonacci(n) { 
 var fibarr = [];
 var i = 0;
 while(i<n) {
  if(i<=1) {
   fibarr.push(i);
  }else{
   fibarr.push(fibarr[i-1] + fibarr[i-2])
  }
  i++;
 }

 return fibarr;
}

后续工作则是利用 canvas 的 arc 方法进行曲线绘制。

DEMO

数组最大差值计算

Q7 找出下列正数组的最大差值比如:

输入 [10,5,11,7,8,9]

输出 6

此题旨在测试对数组最大值查找的基本掌握。显然,最大差值等于数组中的最大值与最小值之差。


 function getMaxProfit(arr) {

  var minPrice = arr[0];
  var maxProfit = 0;

  for (var i = 0; i < arr.length; i++) {
    var currentPrice = arr[i];

    minPrice = Math.min(minPrice, currentPrice);

    var potentialProfit = currentPrice - minPrice;

    maxProfit = Math.max(maxProfit, potentialProfit);
  }

  return maxProfit;
}

随机字符串生成

Q8 随机生成指定长度的字符串

实现一个算法,随机生成指定长度的字符串。

例如给定长度 8,输出类似 '4ldkfg9j' 的结果。


function randomString(n) { 
 let str = 'abcdefghijklmnopqrstuvwxyz9876543210';
 let tmp = '',
   i = 0,
   l = str.length;
 for (i = 0; i < n; i++) {
  tmp += str.charAt(Math.floor(Math.random() * l));
 }
 return tmp;
}

module.exports = randomString; 

DOM类名查找实现

Q9 实现类似getElementsByClassName 的功能

自定义一个函数,查找特定 DOM 节点下包含指定 class 的所有子 DOM 节点。禁止使用原生提供的 getElementsByClassName 或 querySelectorAll 等查找函数。


function queryClassName(node, name) { 
 var starts = '(^|[ \n\r\t\f])',
    ends = '([ \n\r\t\f]|$)';
 var array = [],
    regex = new RegExp(starts + name + ends),
    elements = node.getElementsByTagName("*"),
    length = elements.length,
    i = 0,
    element;

  while (i < length) {
    element = elements[i];
    if (regex.test(element.className)) {
      array.push(element);
    }

    i += 1;
  }

  return array;
}

二叉查找树构建与特性

Q10 使用JS 实现二叉查找树(Binary Search Tree)

完整实现概率较低,但重点考察对二叉查找树的理解及其基本特性的实现。二叉查找树(Binary Search Tree),也称二叉搜索树或有序二叉树,定义为:一棵空树,或满足以下性质的二叉树:

  1. 任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  2. 任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  3. 任意节点的左、右子树也分别为二叉查找树;
  4. 没有键值相等的节点。二叉查找树相比其他数据结构的优势在于查找和插入的时间复杂度较低,为 O(log n)。它是基础性数据结构,用于构建集合、multiset、关联数组等更抽象的数据结构。

前端面试算法题概览

在编码时需充分理解二叉查找树的特性,首先需定义好每个节点的数据结构。


class Node { 
 constructor(data, left, right) {
  this.data = data;
  this.left = left;
  this.right = right;
 }

}

树由节点构成,从根节点延伸至子节点,因此具备基本结构:一个根节点,以及添加、查找和删除节点的方法。


class BinarySearchTree {

 constructor() {
  this.root = null;
 }

 insert(data) {
  let n = new Node(data, null, null);
  if (!this.root) {
   return this.root = n;
  }
  let currentNode = this.root;
  let parent = null;
  while (1) {
   parent = currentNode;
   if (data < currentNode.data) {
    currentNode = currentNode.left;
    if (currentNode === null) {
     parent.left = n;
     break;
    }
   } else {
    currentNode = currentNode.right;
    if (currentNode === null) {
     parent.right = n;
     break;
    }
   }
  }
 }

 remove(data) {
  this.root = this.removeNode(this.root, data)
 }

 removeNode(node, data) {
  if (node == null) {
   return null;
  }

  if (data == node.data) {
   // no children node
   if (node.left == null && node.right == null) {
    return null;
   }
   if (node.left == null) {
    return node.right;
   }
   if (node.right == null) {
    return node.left;
   }

   let getSmallest = function(node) {
    if(node.left === null && node.right == null) {
     return node;
    }
    if(node.left != null) {
     return node.left;
    }
    if(node.right !== null) {
     return getSmallest(node.right);
    }

   }
   let temNode = getSmallest(node.right);
   node.data = temNode.data;
   node.right = this.removeNode(temNode.right,temNode.data);
   return node;

  } else if (data < node.data) {
   node.left = this.removeNode(node.left,data);
   return node;
  } else {
   node.right = this.removeNode(node.right,data);
   return node;
  }
 }

 find(data) {
  var current = this.root;
  while (current != null) {
   if (data == current.data) {
    break;
   }
   if (data < current.data) {
    current = current.left;
   } else {
    current = current.right
   }
  }
  return current.data;
 }

}

module.exports = BinarySearchTree; 

总结

以上就是本文的全部内容,希望这些内容能对各位的学习或工作有所帮助。如有任何疑问,欢迎留言交流。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章