如何更好地应对编程面试

2025-06-09

如何更好地应对编程面试

如何更好地应对编程面试

想提高面试技巧?关键在于方法——本指南将逐步讲解如何准确回答 Facebook、亚马逊、微软、Netflix 或谷歌等公司的编程面试问题。

本文将涵盖很多内容。它将引导你完成一个常见的技术面试问题(白板面试或非白板面试),你将接触到以下内容:

  • 克服紧张情绪所需的心态
  • 面试过程中的每一步
  • 需要复习哪些图案

还有更多。让我们先解决面试中的心理问题,然后再采取切实可行的措施来解决这些问题。

克服紧张

软件工程和技术面试总是让人紧张。我们都知道这一点,但却很少问为什么。

为什么这类采访会让人产生如此恐惧的感觉?

确实,没有什么后果。

最糟糕的情况是,你无法正确表达他们想要的算法。或者你无法给出某个东西的正确定义。那么你很可能就得不到这份工作了。

这可不是什么好结果,但还有更糟糕的事情。你完全可以回家,补习一下错过的知识,然后尝试申请其他学校。

但知道这一点似乎没有帮助,原因如下。

我们的恐惧通常源于不确定性。也就是说,我们认为自己可能会遇到一个我们不知道如何解决的问题或挑战。

但事实并非如此!

首先,采用正确的方法(本文的其余部分将深入探讨),您可以解决任何问题。

其次——确实有可能你会被问到一些完全出乎意料的问题。但大多数情况下,面试官确实了解你的想法。作为一个经历过多次面试的人,我知道我们希望你表现出色。

如果仍然感到紧张,还有其他解决方法。一些可能有帮助的方法包括每天冥想、吃健康的饮食来补充大脑能量,以及定期进行有氧运动

如果你完全失去意识该怎么办

几乎任何技术挑战,只要方法得当,都能找到解决问题的方法。但如果你真的不知道从何入手,该怎么办呢?

因此,让我们快速解决一个问题——如果您真的不知道,请按照以下步骤操作。

假设你是一名前端工程师,拥有几年Javascript单页应用开发经验。在一次面试中,你被问到以下技术问题。

何时会在两个后端系统之间应用异步通信?

你僵住了,胸口突然一阵紧缩。你从未接触过任何后端系统,也忘了这asynchronous意味着什么。有几秒钟,你盯着面试官,思绪却飘忽不定。

以下是解决此问题的两种可能方法:

  1. 将其与你做过的事情联系起来
  2. 强调对学习和从事这些事情的兴奋程度

第一个回应是有效的,因为它仍然允许您展示您的经验:

我没有直接开发过后端系统,不过你能再提醒我asynchronous一下“后端”是什么意思吗?嗯,一种允许工作独立于主应用线程进行的编程形式?我用 React 做过类似的事情——有时通过 REST 端点将数据插入数据库需要一些时间,但我们希望立即反馈给用户,告知数据正在被持久化。所以**我的猜测*是,当你想让一个进程在等待其他进程完成的同时执行某项操作时,它就变成了后端。*

在这种情况下,你所说的内容可能并非面试官 100% 想听到的,但你展现了一些技术敏锐度。你还可以加入一些关于过去经历的讨论。

另一方面,如果你根本找不到任何可以与这个问题联系起来的东西怎么办?不妨谈谈你有多兴奋,以及你如何学习,这可能是一个不错的选择:

说实话,我不太确定,但我听说过这个术语,asynchronous而且很想了解更多关于后端系统的知识。这次采访结束后,我一定会去了解一下。您有什么推荐的书籍或文章可以作为入门吗?

白板算法面试好吗?

本课的剩余部分将讨论如何解决标准化数据结构和基于算法的问题。它仍然适用于一些小样本的挑战,例如“这里有一个基本设置,用一些脚手架实现一个 REST API ”。

是的,白板算法面试确实存在争议。然而,它仍然存在一些原因。首先,它向面试官发出了几个强烈的信号,例如:

  • 候选人能否在他人面前清晰地思考(本课旨在解决的问题)
  • 他们听起来像是已经为面试做好了准备吗(这是职业道德的信号)
  • 他们是否具有合理的逻辑能力?
  • 他们能区分好的解决方案和坏的解决方案吗?
  • 他们对计算机科学基础知识的掌握如何?

其次,它们很容易大规模实施,如果你是一家每年需要招聘数千名员工的企业集团,这一点尤其重要。

是的,有家庭作业、专题采访,以及为期一周的“试用”期。我相信这些都是很棒的方法。

然而,“你能解决我面前的这个问题吗”data structure和算法问题仍然是大多数软件公司的标准。

让我们想想如何解决这些问题。

优秀受访者的应对方法

在我们深入探讨之前,这里有一个重要的提示。为了使这一切顺利进行,你必须熟练掌握数据结构和算法。

你对这些话题练习得越多,就越容易将pattern它们变成-词缀。面试的时候,你也能更容易地从记忆中回忆起它们。

当然, AlgoDaily 的高级课程每日新闻简报问题是一个很好的起点。其他建议可以在我们关于如何准备技术面试的课程中找到。

综上所述,以下是我们推荐的解决白板问题的典型步骤。我们将花大量时间深入探讨每一个步骤。

  1. 运行几个(1-3)个示例输入来了解问题
  2. 通过询问人类如何做到这一点,快速解开暴力解决方案
  3. 将暴力破解方法与模式、数据结构或计算机科学技术联系起来
  4. 优化并再次运行步骤 1 中的相同测试用例
  5. 如果有时间,请指出边缘情况并改进问题

面试期间的沟通

面试很大一部分是对你的沟通能力的考验,这不是什么秘密。软件工程是一项团队运动。

孤独天才程序员的神话终究只是个神话。尤其对于那些需要数十万工程师参与的大型、复杂、影响深远的项目来说,更是如此。

您如何展现强大的沟通技巧?

你必须继续说下去——我再怎么强调也不为过。除非你需要完全安静的环境来思考——这没问题——否则你应该说出你的想法。

  • 如果你遇到困难,请告知面试官
  • 如果你不明白这个问题,可以提出更多澄清问题
  • 如果你不知道发生了什么,就说你需要更多背景信息
  • 如果您需要提示,请告诉他们!

如果你害羞,完全没问题。但说到面试,你要知道,你和这个人一起工作的可能是这个人,也可能是和你拥有类似资质和技术能力的人。无论好坏,面试官在面试中对你的看法,都决定了他们最终会如何看待你。尽量保持友好和坦诚的态度,哪怕只是为了争取这份工作所需的几个小时。

如何收集需求

让我们继续学习一些实用的技术面试技巧。我们可以看看“从零到末尾”的问题。题目如下:

编写一个方法,将数组中的所有零移动到其末尾。

你首先应该做的就是明确需求。除非你确切知道问题所在,否则你没必要去想解决方案。原因如下:

应聘者:太棒了,零在后面,非零在前面。是这样的吧?

看起来很简单。为什么不直接开始解决呢?因为面试官可能会说:

面试官:另外,请注意,你应该保持所有其他元素的顺序。哦,这需要在 O(n) 时间内完成。

如果你没有考虑到这一点,你可能会走上一条非常糟糕的道路。务必用自己的话重复问题,并进行深入的澄清。了解所有需求,并重复一遍,让他们知道你已经完全掌握了问题的全部内容。

候选人:所以我们想把所有零移到后面,同时把非零放在前面。我们还想保持非零元素原来的顺序,并且算法应该以线性时间运行。

采访者:完全正确。

从输入和输出开始

接下来要做的就是要么索要几个样本数组,要么自己设计一个。开始构建你的测试用例。这有助于你开始处理如何转换输入以获得输出。

尝试从非常小的输入开始,随着样本数量的增加逐渐增加其大小。你可以这样说:

候选人:这个问题很有意思。好吧,为了确保我理解了我们想要的转换和结果,我来举几个例子。如果我得到[0, 1],我们想要[1, 0]返回什么?

面试官:是的,没错。(应聘者开始思考如何移动第一个例子中的那个零)

候选人:嗯,对于那个,我们只需要将0和 交换1。现在,如果给出[1, 0, 2, 0, 4, 0],我希望[1, 2, 4, 0, 0, 0]返回。

采访者:正确。

候选人:然后[0, 0, 4]变成[4, 0, 0]。嗯……

如何找到强力解决方案

现在您已经尝试了一些输入和输出,要问的主要问题是:

If a machine were not available, how would a human manually solve this?

记住,计算机只是工具而已。在它们出现之前,人类只能手动计算。所以,问问自己如何手动计算,是开始集思广益解决问题的好方法。当循环和条件语句不可用时,你可以用简单的英语表达你需要做什么。

候选人:嗯,是的,对于这些例子,结果总是返回一个非零数组,最后返回一个零数组。我思考了一个非常基本的实现,我一直在做的是:迭代,找到非零值,然后把它们放进另一个temp数组。然后,我一直用0s 填充结果数组的剩余部分,直到得到原始长度。

面试官:有意思。想把那个实现写出来吗?

使用伪代码来澄清你的想法

除非算法非常简单,否则您需要先编写伪代码。

对于暴力破解方案尤其如此。面试官可能第一遍只接受伪代码,然后可能会要求你用剩下的时间求解并编写一个优化方案。

此外,如果发现有害错误,用伪代码思考更容易修改。它最初的样子可能如下:

temp = []
zero_count = 0
iterate through array:
  if nonzero, push to new temp
  if zero, increment count
for zero_count times:
  push to temp
return temp

如果面试官修改问题使其稍微复杂一些,这说明你的思路是对的。他们可能会添加约束(在常数时间内完成),或者显著增加输入量。根据我的经验,大多数面试官会计划做一道简单题和一道难题。

面试官:太好了,现在你可以在不实例化新数组的情况下做到这一点吗?

此时别慌,也别因为通过了第一部分而兴奋不已。现在该把我们的暴力破解方案与改进技术结合起来了。我们将介绍几种改进方法。

如何利用模式和抽象进行优化

完成大约 50-100 个模拟面试题后,你就会开始认识到可以利用的模式。这里有一个例子:If you want speed, you usually need more space/memory.这与下一节关于如何使用数据结构的内容特别相关。

回顾目前为止解决方案中的每个步骤,思考是否有任何潜在的简化或分解方法。有什么方法可以降低其复杂性?

一个技巧是从更高的层次思考你正在做的事情。我的意思是,让你自己摆脱逻辑的束缚,回到输入到输出的过程。在上面的例子中,我们通过连接数组将零移动到末尾,但实际上我们需要做什么呢?这个过程可以理解为:

  • 识别非零元素
  • 将元素放在不同的索引处
  • 找出0有多少个

拥有上述清晰步骤的好处在于,您现在可以探索完成每个步骤的其他方法

  • 例如,为了识别非零元素,您可以遍历数组并使用条件。
  • 或者,您可以使用一种filter方法。
  • 如果这没有帮助,您还可以zeros连续查找多个,然后splice输出一个新的数组。

还要问自己一些问题:What am I trying to do in plain English?

取得进展的另一个非常简单的方法是尝试调整输入。

  • 如果它是一个集合,排序分组有帮助吗?
  • 如果它是一棵树,我们可以将它转换成数组或链表吗?

如果调整输入没有产生任何影响,也许是时候进行更大的转变了。

引入数据结构或抽象数据类型

这时,学习数据结构(以及实现和使用它们的经验)就会非常有帮助。如果你能找出瓶颈所在,就可以开始尝试用数据结构来解决这个问题,看看是否能带来性能或空间上的提升。

回到我们之前做的“从零到末尾”的问题,我们的瓶颈很可能是步骤putting elements at different indexes。在这种情况下,我们可能会意识到使用counter变量是有益的。

注意,代码data structure不需要太复杂。在我们的例子中,我们实际上只引入了一个int变量——但有时这已经足够了。

那么应该计算什么呢counter?好吧,一旦我们将数组拆分为非零值([1, 2, 3])和零值([0, 0, 0]),我们实际上只关心非零值在哪里结束。

因为我们不需要担心数组中非零元素之后的内容,所以我们可以简单地保留一个单独的指针来跟踪最终数组的索引。它会告诉我们从哪里开始添加零。

然后我们可以编写以下伪代码来利用此策略:

insert_position = 0
for i in nums
  if i is not 0
    increase insert_position
    keep it in insert_position
  fill the rest in with 0

尽管有两个循环,时间复杂度仍简化为O(n)。然而,由于我们使用相同的数组,空间复杂度是恒定的,所以我们得到了改进!

战术数据结构速查表

需要快速访问集合中的元素吗?数组已经在内存中保存了位置。

需要快速插入数据?将其添加到哈希表或链表。

需要在 O(1) 时间内求出最大值或最小值?那就用堆吧。

需要建模连接吗?那就去graph那里吧。

数据结构掌握得越多越好。你可以查看课程表,了解绝对要求。

尝试一些更高级的结构也很有用(但并非必需),比如 AVL 树、字典树、优先级队列、后缀数组和布隆过滤器。虽然它们不太可能被用到,但在工业界却很有用,而且在面试中拿出来会给人留下深刻印象。

关于哈希表的特别说明:

好好了解一下这些家伙!它们可以用于数量惊人的解决方案。许多问题可以简化为在大型数据集合中搜索元素、查找重复项或存储/检索项目。哈希表/哈希映射在这些方面表现非常出色,所以请始终牢记它们。

如果其他方法data structure没有帮助,那么也许是时候尝试一种老式(但可靠)的技术了。

介绍一种计算机科学算法技术

有一些技术是每个人都应该了解的。这些技术通常会在Intro to Algorithms课程中讲解,以便对算法进行分类。

它们通常不仅对面试有用,而且对一般的软件工程工作也有益,所以要了解它们!

分而治之尝试将问题分解成更容易思考或解决的子问题。这样可以……

递归——看看能否利用一个调用自身的函数。尤其要注意recursion树形结构。

记忆化- 你在暴力破解中生成的部分结果是否可以用于更大或不同的输入?如果可以,可以利用某种缓存。你可以在内存中存储(或创建并存储在内存中)哪些数据来帮助算法?

贪婪graph——思考每次迭代或每一步的最佳走法是什么。每一步是否有一个显而易见的最佳走法?这在像 Dijkstra 算法这样的遍历问题中经常出现。

如果以上方法都不起作用该怎么办

所以,上述任何模式、数据结构或技术都无法解决这个问题。该怎么办?

您有两个选择。

多问一些问题。

或者

我说,我卡住了。能给我点提示吗?

保持沟通!面试官通常很乐意给出提示——事实上,这是他们的工作。有些面试问题会很遗憾地包含一两个“关键直觉”,你必须先理解它们才能找到答案。

有了可行的解决方案之后

这里有一个关键点,需要花点时间才能搞定。在为优化方案编写了伪代码后,请逐步手动运行 1-3 个示例输入,确保伪代码能够正常工作。警告:你可能会感到紧张,并且有时会忘记进度,但这非常重要。

优秀的工程师会彻底测试他们的代码,并能够单步执行逻辑。在伪代码解决方案和在白板上写代码之间,正是展示这一点的好时机。

此时,您还可以消除错误的假设或做出重要的认识(“哦,等等,我们应该使用Map而不是 JS 对象”)。

候选人:我们从 开始[1, 0, 3],我认为这是一个很好的测试候选。好的,从 开始1,我们看到它不是零,所以它可以保持不变。我们要转到下一个元素,所以让我们增加最终的数组索引计数器。现在我们有0,我们跳过它。好的,3不是零,我们的计数器在 ,1所以我们把它放在 后面1,这样就得到了[1, 3]。太棒了!然后我们0在末尾加上 a ,就得到了我们想要的结果。

面试官可能会说“太好了,我们开始写代码吧”,或者他们可能会想看看你对自己的解决方案有多自信。如果输入输出都通过了,你应该会感觉良好,可以继续前进了。

注意:如果您要在白板上进行面试,请购买磁性白板干板并在其上练习手写代码。

人们在白板上编码时没有考虑很多事情:主要是空间管理,还有如何使用较短的变量以及水平书写。

无论如何,您现在已经编写了以下代码:

function zerosToEnd(nums) {
    let insertPos = 0;
    for (let i = 0; i < nums.length; i++) {
        if (nums[i] != 0) {
            nums[insertPos++] = nums[i];
        }
    }

    for (let j = insertPos; j < nums.length; j++) {
        nums[j] = 0;
    }

    return nums;
}

一旦您写出了解决方案代码,技术部分就应该完成了。

现在面试将转向面试官的问题。确保你准备好了问题,并尽量不要考虑你的表现。

到那时,无论发生什么,你都无法掌控。所以,要放眼未来,专注于面试官的当下。即使面试结果不如你所愿,保持镇定也会让面试官觉得你更专业。

希望本指南对您有所帮助。请记住,任何编程挑战都可以通过正确的方法和正确的心态来解决。祝您好运!

本课程最初发布于https://algodaily.com,我在那里维护技术面试课程并为雄心勃勃的开发人员撰写思考文章。

鏂囩珷鏉ユ簮锛�https://dev.to/jacobjzhang/how-to-get-better-at-approaching-coding-interviews-nnp
PREV
JavaScript 资源 - 播客、书籍、视频和教程资源 JavaScript 开发
NEXT
无需专业经验即可获得第一份软件工作