机器之心编译
参与:李诗萌、张倩、蛋酱
春招来临,「如何拿到大厂 offer」成了每个求助者最关心的问题。在本文中,谷歌大脑高级软件工程研究员、强化学习框架「多巴胺」()作者 Pablo 分享了他拿到谷歌 offer 的经验。这份「谷歌面经」不仅适用于谷歌的软件工程师职位,对申请其他公司的软件工程师及其他职位(如研究科学家)也有帮助。
大家经常问我,怎么才能拿到谷歌的 Offer?虽然这个问题没有固定答案,但我还是有一些可以帮助其他人(包括我自己)的技巧。
我在谷歌的面试过程不算完美,但我确实感觉整个过程都很好、很客观。无论结果如何,请记住:你的个人价值不该由你是否得到了 offer 来定义。
引言
我应该申请谷歌的职位吗?这是另一个常见问题。答案几乎总是肯定的!去谷歌面试不仅可以测试你的极限,还能让你发现自己的不足。如果你尝试过,就算最后没能成功,我也保证你会成为更加强大的程序员和面试官。
在获得 PhD 学位后,我立志成为一名学者,但那时(大概是 2011 年)的就业市场真的非常糟糕。在上司的建议下,我申请了谷歌的职位。这是我申请的唯一一份业界工作,也是我在业界最感兴趣的工作。
在提出申请后,我为面试做了许多准备。我确信,如果申请的那天就进行面试,我是无法通过的:花时间准备面试是非常必要的。到面试时,我感觉自己已经准备得非常充分了。
最终,努力得到了回报:我收到了加入谷歌匹兹堡办公室的 offer,从 2012 年起,我成为了一名谷歌软件工程师(SWE)。
我在谷歌匹兹堡办公室的第一张办公桌。
如何申请谷歌?
你可以访问谷歌求职网站找到合适的职位:;
推荐一般也有用。如果谷歌有你认识的人,可以请他们内推。如果你不认识任何在谷歌工作的人,而且你已经申请了一段时间,但仍没有收到任何回音,可以发简历给我,看我能不能帮上忙。请注意,这种做法依然无法保证你得到面试机会。我不太清楚面试筛选标准,因此无法在这方面给出建议。
如何准备谷歌面试?
面试(至少)包括三个部分:编程、算法和数据结构,以及个人品质。谷歌(和其他公司)经常举办面试研讨会,你可以在会议中进行模拟面试;如果有条件的话可以搜索并加入这些研讨会。
编程
你要能写出函数式代码。而且理想情况下,你写的代码要可以立即编译或运行。语言不重要,但你要指定面试时想使用的语言。因此,要确保你非常了解自己选的这门语言。此外,伪代码不是一种语言。
1. 用 编程
如果你写代码时依赖 IDE,请试着用 !无论你用什么程序写代码,请关闭语法高亮和自动补全功能。尝试用什么都没有的 vim 写所有代码(即便是现在我还是在用非常简单的 vim 写大多数东西三种优雅的访问谷歌的方法,包括这篇文章)。你也可以用 Emacs。
2. 熟能生巧
我在准备面试时,主要用 C++ 写打码,所以我决定专注于此。我发现了一个在线的编程比赛,这个比赛有之前比赛的记录,这样可以「假装」正在比赛。好处在于,这个在线服务可以以编程方式检查代码的语法和算法的正确性。经过努力练习,我终于从头写出了可以编译及解决问题的 C++ 代码。在此之前,我重复了千千万万遍。
此外,我还花了好长时间搜寻需要的库,以及如何执行正确的 I/O 等。
我不记得用过哪些网站,但 中有针对实践问题的部分,似乎可以达到相同的目的。
地址:#/u/
也可以浏览 这样的网站,网站中有大量过去的谷歌面试题。试着解出所有的题。
地址:
3. 在白板上写代码
试着在白板上写代码(如果你没有粉笔或白板,也可以在一张纸上手写)。在白板上写代码的感觉截然不同,但谷歌面试中有这项要求。
有经验当然最好。我建议你在白板上写完整的程序,然后再在电脑上编码,并确保可以一次编译或运行成功。如果无法成功,请再试一次。
让别人围观你在白板上写代码也非常有用,可以帮助你适应可能出现的紧张情绪。
有几处语法错误是可以接受的,但如果代码太粗糙,而且错误过多,面试官可能会觉得你不熟悉自己选的语言。
算法和数据结构
我准备面试时看的书也是我读大学时用的书—— H. 、 E.、 L. 和 Stein 写的《算法导论》( to )。我肯定,还有很多书都可以帮你达到相同的目的,只不过这是我随手就能拿到的书。
有一些算法和数据结构是你绝对要知道且熟悉的:
排序:了解不同的排序方式。知道各种排序算法的适用场合及复杂性。链表:什么是链表?你能否从头写出一个链表?插入、删除和搜索的复杂度是多少?什么时候使用链表?链表是否有不同的类型?哈希:什么是哈希函数?怎样的哈希函数称得上好的哈希函数?什么是哈希冲突()?如何解决冲突?平均复杂度是多少?最坏情况下的复杂度是多少?二叉树:什么是二叉树?你能从头写出一个二叉树吗?什么是二叉搜索树?搜索、插入、删除的复杂度是多少?平衡树意味着什么?复杂度是多少?动态编程:什么是动态编程?何时用动态编程?你是否会用动态编程算法解决问题(你可以从书中挑选一个例子进行练习)?图算法:图的遍历算法(BFS/DFS)。有向图和无向图。你能从头写一个图数据结构吗?什么时候用图?修改图有哪些不同的方法?
上面列出的内容并非可能考到的全部内容,但我认为这是一个合理的基础。我希望你知道上述所有问题。
和编程一样,这部分的重点也是熟能生巧。解决不同问题时,请在思考后使用最适合的数据结构。
前面已经提示过:无论写什么样的代码,都要进行复杂度分析(即 big-O)。我个人总是在面试者写完代码后问他们这个问题,因为这表示他们可以分析自己实现代码的效率。本文后面的内容会提到,即便你只能提供一个非常简单的解决方案,但如果你能进行准确的分析,也会有很大的帮助。
个人性格
这是很难准备的一部分,但也很重要。面试官会问自己的问题之一是:我想和这个人一起工作吗?如果你是个天才,任何扔给你的问题都能解决,但你却在面试期间表现得像个混蛋,聘用你的可能就很小了。
在这方面,我也不能建议你做什么样的具体准备,但在面试过程中要记住几点。
面试中
如果你已经安排进入面试了,首先要恭喜你,这已经很了不起了,因为不是每个人都能参加面试。这些重点你要记住:
将面试视为一次平等的对话,而非单方面的询问。尽管在面试的双方是权力不对等的,但我们并不是要骗你或者让你犯错。事实上三种优雅的访问谷歌的方法,我们大多是在默默为你加油。
说出你的思考过程。确保将头脑的思路过程清晰地展示出来,尤其是在白板上写代码之前。作为面试官,我们需要一些证明你表现良好的证据,说明白你的思路就有助于我们收集证据。此外,如果你陷入了一些我们认为不值得花太多时间的问题,我们可以及时帮你拉回来。如果你不说话,而直接写了错误的代码,我们无法知道你是真的不懂,或只是误解了问题。另一方面,如果你默默写出了完美的代码,我们也不知道你是真的明白,或许你只是见过这个问题。
简单的解决方案是很好的起点。不要勉强自己想出最高效的方法,先给出简单的方案是很好的策略。
为什么这么说呢?原因有很多:
即便这个问题看起来微不足道,但也经常有一些意料之外的棘手情况。通过简单的方案更容易解决这样的问题;简单的方案可以很快地写在白板上,有利于面试官评价你的表现;简单方案的复杂度分析比复杂方案的复杂度分析要容易得多;简单方案可以快速写出来,之后就可以转向寻找更复杂的解决方案,但你至少有一个可以作为基准的简单方案;对面试官来说,理解简单方案比理解复杂方案更容易。你肯定希望面试官能理解你的方案,如果一个复杂方案让面试官都困惑了,不利于得分;过一遍简单方案相当于对代码进行「手动分析」,有助于你挑出冗余的工作,还可以优化代码;简单的方案也可以是深入交流的开始。既然已经有了一条解决方案,然后你就可以询问面试官,是否想要更好的方案;最后,要确保你已经告知面试官,你是以一个简单方案开始(不代表你只能给出简单方案)。
可以简化假设。做一些简单的假设能帮你更清晰地思考问题,原理和「给出简单方案」类似。这个的好处在于可以表现出你有解构问题的能力,代表你能分辨出可能会造成严重问题的部分。
使用测试示例。找一些可以测试代码的测试示例,试着预测边际情况(例如空列表、越界索引、预料之外的特殊字符等),这样有助于保证代码的准确性,也有利于征服面试官。举例真的很有用,面试官甚至可能会添加一些测试示例来检验你可能遗漏的其他边缘情况。
花几分钟整理思路。我虽然建议你讲出思考过程,但也不用勉强自己一直讲话,尤其是在你还没整理好思路的情况下,不停讲话就可能导致你进入误区。可以提出申请「我能花两分钟整理一下思路吗?」,重要的是要让面试官知道你在干什么。如果你觉得整理思路的时间太长,可能是因为你对问题的某一部分感到困惑,这就是下一个问题。
可以寻求帮助。如果感到困难,你可以寻求帮助,但要具体说明问题在哪。一般可能是你误解了问题,所以没能注意到问题中重要的点,有时也可能是面试官自己忘了提到问题中重要的部分。我就遇到过这种情况,面试者似乎被难住了,但我给了一点帮助后,他们就解决了问题。
可以有所不知。我参加面试时,实现了一个自定义数据结构,来简化解决方案中剩下的代码。面试官问我:「你为什么不用映射?」,我告诉他「我不知道什么是映射」。面试官很快在白板上给我解释了映射的语法(这是比我的「用户数据结构」更简洁的版本),然后我就更快地解决了问题。我不知道是否因为承认自己的无知而得分,但最终得到了这份工作。
没有「唯一正确」的答案。至少在大部分面试中都没有唯一正确的方案,我最喜欢的是可以快速陈述、易于理解、同时存在简单解和复杂解、而且很容易就能变复杂的问题。我认为大多数面试官都会问这些问题。这意味着我们并没有预设答案,你只要尽你所能就可以了。
不要问你给出的答案是否正确。最好是用测试用例验证你给出的答案,并根据测试结果证明答案是正确的。
可以有分歧。和面试官有分歧没关系,但是要用礼貌的方式表达。用具体工具(比如代码和测试用例)支持你的观点;如果只有口头讨论可能会引起误会,这样会消耗有限的时间。试着理解面试官的观点(尽管他们看起来是错的),并冷静地让面试官理解你的观点。
将每次面试都视为一个崭新的开始。如果你觉得哪次面试很糟糕,请将它搁置在一边,或者等一切都结束后再想,然后开启下一次面试。我知道这说起来简单做起来难,但你得明白,下一次的面试官不会知道你之前的表现。就算你有一次面试的成绩很糟糕,但你也可能通过下一次面试。
如果有时间,提点问题。我一般都在最后给面试者留出时间,让他们问一些有关在谷歌工作的常见问题,比如你的角色或经历等。如果你有问题,也许表示你对这份工作确实很有热情。如果你没有问题的话,那可以向面试官请教,可以请问他们在谷歌的角色和经历。不要问「我在面试中要怎么做?」或「正确答案是什么?」这样的问题,因为我们不会回答这样的问题,这可能会使场面变得尴尬。
面试后
再一次恭喜,你已经完成了面试。后续过程大致是这样的:
每个面试官都会给你写反馈,给出「建议录用」或「不建议录用」的意见。面试官之间看不到其他的反馈。
你的资料中会包括:简历、面试反馈、过去的面试结果等,会有几个招聘小组审查这些资料。这些小组由一些没有面试过你的谷歌员工组成,他们会根据你的档案袋给出录用建议。
根据招聘小组的决定,可能会发生以下几种情况:
你拿到了 offer;你需要进行额外的电话面试。这不一定意味着你的面试表现不够好,还可能是在面试过程中未能正确评估某种能力;可能会让你担任其他职务。这并不是件坏事,这只意味着招聘小组根据资料,认为你更适合担任其他职位。此间也会有一些附加面试,归根结底也是件好事;你没能得到 offer。这有点遗憾,在谷歌拿到 offer 确实不那么容易,但你为这次面试所做的努力,以及这次面试经历本身,都会在其他面试中帮到你。另外,一年后你也可以重新申请谷歌职位。我曾审查过某人的资料,他起初没有得到 offer,但在一年后重新提出了申请,最终得到了 offer。
写在最后
尽管本文所写大部分都是关于谷歌 SWE 职位的面试,但这些建议也适用于其他公司的 SWE 职位。几年前,我参加了 的面试,也用过文中提到的所有技巧。最后我得到了 offer,但因为我受邀加入 Brain(我现在很高兴地在这里工作),所以拒绝了 的 offer。
这篇文章也能从某种程度上帮到非 SWE 职位的求职,其中我最熟悉的就是研究科学家(RS)职位。我曾主持过一些 RS 求职面试,但还不足以提供具体的指导。但我想说的是,即便是面试 RS,你也要通过编程面试。我曾在编程面试中遇到过理论很强但实操很弱的人,最后我给了「不予录用」的建议(这个人没加入谷歌,我也不知道他是否拿到了别的 offer)。
此外,还有一些其他人分享的很有价值的建议。如 Mekka 和 Steve Yegge都分享了一些很好的建议。还有人推荐了《程序员面试金典》( the )这本书。
原文链接:
评论留言