在前端面试中,算法题通常不会像纯算法岗那么难,但也会考察一些基础逻辑和数据处理能力。以下是一些常见题型和口语化的回答思路:
1. 数组去重
问题 :[1, 2, 2, 3]
怎么去掉重复的数字?
回答 :
"前端最常用的是用 Set
,因为 Set
天生不能存重复值,直接 [...new Set(arr)]
一行搞定。
如果不用 ES6,可以用 filter
遍历,检查当前元素第一次出现的索引是不是等于当前索引,比如 arr.filter((item, index) => arr.indexOf(item) === index)
。
如果面试官问性能,Set
是 O(n),而 filter
+ indexOf
是 O(n²),数据量大时用 Set
更好。"
2. 反转字符串
问题 :把 "hello"
反转为 "olleh"
。
回答 :
"最简单的是 str.split('').reverse().join('')
,先拆成数组,反转再拼回去。
如果不用 API,可以写一个循环,从后往前遍历字符串,把字符一个个拼到新字符串里。
还可以用递归,每次取最后一个字符加上剩下的部分反转的结果。"
3. 统计字符串中出现最多的字符
问题 :"abbccc"
中哪个字符出现最多?
回答 :
"我会用一个对象(比如 const obj = {}
)当哈希表,遍历字符串,把字符作为 key,出现次数当 value 存进去。
然后遍历这个对象,找出 value 最大的 key。
注意边界情况,比如空字符串或者多个字符出现次数相同。"
4. 扁平化数组
问题 :把 [1, [2, [3]]]
拍平成 [1, 2, 3]
。
回答 :
"ES6 可以直接用 arr.flat(Infinity)
,参数 Infinity
表示不管多少层都拍平。
如果自己实现,可以用递归:遍历数组,如果当前项是数组就递归调用,否则放到结果里。
也可以用 reduce
结合递归一行搞定:
arr.reduce((res, item) => res.concat(Array.isArray(item) ? flatten(item) : item), [])
。"
5. 手写防抖/节流
问题 :滚动事件频繁触发,如何优化?
回答 :
"防抖(debounce)是等用户停下来了再执行,比如搜索框输入。代码大概是用 setTimeout
,每次触发先清掉之前的定时器,再设新的。
节流(throttle)是固定时间执行一次,比如拖拽元素。可以用时间戳判断,或者用 setTimeout
的锁标志。
区别是防抖可能一直不执行(如果一直触发),节流则保证每隔一段时间执行一次。"
6. 判断回文
问题 :怎么判断 "abcba"
是回文?
回答 :
"最简单的就是转成数组 reverse
后和原字符串比较。
或者用双指针,一个从头一个从尾往中间走,比较字符是否相同,遇到不一样的直接返回 false。"
7. **实现 Promise.all
**
问题 :手写 Promise.all
。
回答 :
"Promise.all
接收一个 Promise 数组,全部成功时返回结果数组,有一个失败就整体失败。
实现思路是:维护一个计数器和一个结果数组,每个 Promise 完成后把结果放到对应位置,计数器+1。如果全部完成就 resolve,中间有任何一个 reject 就直接 reject。"
8. 二叉树遍历
问题 :二叉树的前序遍历怎么写?
回答 :
"前序遍历是根→左→右。递归写法很简单:
scss
function traverse(root) {
if (!root) return;
console.log(root.val); // 先处理根节点
traverse(root.left);
traverse(root.right);
}
非递归的话用栈模拟,先把根节点入栈,循环里弹出节点、处理它,然后先右后左子节点入栈(因为栈是后进先出)。"
小技巧:
- 先沟通:别急着写,先问清楚输入输出和边界条件(比如数组为空怎么办)。
- 举例说明 :边说边写例子,比如"假设输入是
[1, 2, 2]
,第一步我会..."。 - 优化思路:先写暴力解法,再提优化(比如"这里可以用哈希表减少时间复杂度")。
- 前端关联:提到实际应用,比如"Vue 的 diff 算法里就用到了类似的双指针思想"。
面试官更看重思路是否清晰,代码是否健壮,而不是死记硬背答案。放松心态,就当在和白板讨论问题就好!