前端面试算法编码问题——如何准备
这是前端/网站开发者面试中准备算法编码问题的指南,包括需要了解的概念、面试评分标准和重要的实践问题。
算法编码问题就是可以在 LeetCode 上找到的问题。 算法问题通常具有以下特征:
- 它们不特定于前端领域;可以通过大多数主流编程语言求解。
- 通常附带不切实际的情景。 你在实际开发中不会遇到这样的问题。 有谁曾经不得不反转二叉树或计算字符串中回文子串的数量呢?
- 代码效率(时间和空间复杂度)很重要,要想得到最有效的解决方案需要扎实掌握数据结构和算法知识。
虽然算法编码问题不是前端特有的,但在这些问题中表现出色所需的技能——强大的分析思考能力、有效的沟通能力、熟练掌握常见的数据结构和算法、良好的代码卫生习惯,仍是优秀的前端工程师必须具备的关键技能。 优秀的前端工程师也是优秀的软件工程师,而优秀的软件工程师应该掌握基本的数据结构和算法。 因此,在面试过程中,很多公司仍然会问有关算法编码的问题。 熟悉数据结构和算法对于解决 JavaScript 编码问题和用户界面编码问题也有帮助。
关于算法编码面试的资源有很多,因为它们不特定于前端,所以我们不会在这里详细介绍。 如果您想了解有关算法编码面试的更多信息,我们建议参考Tech Interview Handbook。
示例
- 反转链表。
- 判断字符串是否包含平衡的括号。
- 计算字符串中有多少个子串是回文的。
如何准备
- 选择一种好的编程语言。 如果你想节省准备时间,你可能应该坚持使用 JavaScript 来解决算法问题,尽管需要注意的是 JavaScript 语言不包含某些常见有用的数据结构和算法,而其他语言,如 Python、Java 和 C++则包含。 个人建议使用 Python 来解决算法面试问题。
- 规划时间并按优先级处理主题和问题。
- 将学习和练习结合在一起。
- 通过编码面试备忘清单来加深印象。
请参考Tech Interview Handbook 的逐步指南,了解如何准备算法编码面试。
重要概念
尽管你仍然可能被问到任何算法问题,但公司倾向于对前端工程师候选人采取温和的态度,并且可能不会问与动态规划或复杂图形算法等困难的话题有关的问题。
由于 DOM 是一棵树,优先学习有关树和各种树遍历算法的知识。
类别 | 重要话题 |
---|---|
数据结构 | 数组、映射、堆栈、树、图、矩阵(2D 数组)、集合 |
算法 | 二分查找、广度优先搜索、深度优先搜索、拓扑排序、递归 |
常见 JavaScript 操作
Array
操作 | 时间复杂度 |
---|---|
Array.prototype.concat() | O(m + n) |
Array.prototype.every() | O(n) |
Array.prototype.fill() | O(n) |
Array.prototype.filter() | O(n) |
Array.prototype.find() | O(n) |
Array.prototype.pop() | O(1) |
Array.prototype.push() | O(1) |
Array.prototype.reduce() | O(n) |
Array.prototype.reverse() | O(n) |
Array.prototype.shift() | O(n) |
Array.prototype.slice() | O(n) |
Array.prototype.some() | O(n) |
Array.prototype.sort() | O(nlgn) |
Array.prototype.splice() | O(n) |
Array.prototype.unshift() | O(m + n) |
* n
是数组中元素的数量,m
是要添加的元素的数量。
Map
操作 | 时间复杂度 |
---|---|
Map.prototype.clear() | O(n) |
Map.prototype.delete() | O(1) |
Map.prototype.entries() | O(1),因为它返回一个迭代器。 获取所有条目将花费 O(n)时间。 |
Map.prototype.forEach() | O(n) |
Map.prototype.get() | O(1) |
Map.prototype.has() | O(1) |
Map.prototype.keys() | O(1),因为它返回一个迭代器。 获取所有的 key 将需要 O(n)时间。 |
Map.prototype.set() | O(1) |
Map.prototype.values() | O(1),因为它返回一个迭代器。 获取所有 value 将花费 O(n)时间。 |
* n
是映射中键的数量。
Set
操作 | 时间复杂度 |
---|---|
Set.prototype.add() | O(1) |
Set.prototype.clear() | O(n) |
Set.prototype.delete() | O(1) |
Set.prototype.entries() | O(1),因为它返回一个迭代器。 获取所有条目将花费 O(n)时间。 |
Set.prototype.forEach() | O(n) |
Set.prototype.has() | O(1) |
Set.prototype.keys() | O(1),因为它返回一个迭代器。 获取所有的 key 将需要 O(n)时间。 |
Set.prototype.values() | O(1),因为它返回一个迭代器。 获取所有 value 将花费 O(n)时间。 |
* n
是集合中元素的数量。
算法编码面试评分标准
在算法编码面试中,面试官评估候选人的技能,包括:
- 问题解决: 采用系统和逻辑的方法来理解和解决问题。 将问题分解为更小的独立问题。 评估不同方法及其权衡。
- 技术能力: 能够将解决方案转化为工作代码,并表现出对所使用语言的深刻理解。
- 沟通: 询问问题以澄清细节,并清楚地解释自己的方法和思考。
- 验证: 确定要针对代码进行测试的各种情况,包括边缘情况。 能够诊断和解决出现的任何问题。
有用的提示
- 虚构的想法。 JavaScript 的标准库不包含队列,堆,二分查找等一些有用的数据结构和算法,这可能会使您在 JavaScript 编码面试中感到困难。 但是,你可以问面试官是否可以假装这样的数据结构/算法存在,并直接在你的解决方案中使用它而不实现它。
- 纯函数。 编写纯函数,这样可以使函数具有可重复使用性和模块化性,也就是说,函数不依赖于函数外的状态,并且不会产生副作用。
- 明智地选择数据结构。注意选择数据结构并了解代码的时间复杂度。 熟悉 JavaScript 数组、对象、集合、映射的时间/空间复杂度,如有必要,可以在解决方案中使用它们。 其中一些时间/空间的复杂度在不同的语言中有所不同。 如果可以使用哈希映射在 O(n)的运行时内完成任务,就不要编写 O(n2)的代码。
- 递归边界。
- 如果您已经确定解决问题需要递归,请询问输入大小和如何处理递归栈溢出的情况。 通常情况下,你不必处理它,但是提出这个问题是一个好的信号。
- 深嵌套的数据结构可以具有递归引用它本身的特征,这使得某些操作如序列化变得更加棘手。 问问面试官你是否要处理这样的情况。 通常情况下,你不必处理它,但是提出这个问题是一个好的信号。
实践问题
目前,最好的练习算法问题的平台无疑是 LeetCode。 但是,GreatFrontEnd 提供一些数据结构和算法的练习问题,在其中,您可以练习实现常见的数据结构(堆栈、队列)和算法(二分查找、归并排序)等在 JavaScript 中的操作。