当我最后起头参与编程面试的时候,我所有最心仪的公司都漠视了我。如今回头看阿谁时候,我发现本身其时往参与面试都完全没做任何筹办。固然已经有许多博客文章和册本在讲编程面试,但如今的我做为面试官,坐在桌子的另一边,仍是能看到许多来参与编程面试的人没做任何筹办,或者筹办得很蹩脚。那也就是为什么我起头写那篇指南的原因,刚结业时的我、第一次参与面试的我必然十分想有那么一份指南来指引本身。而从如今起头,我本身也会照着那份指南往做。
多年以来,我在好几家公司工做过,所以我的面试身手得到了很好的磨炼,并且我参与面试的过程也教会了我该说什么、该做哪些筹办,以及若何面试。在那篇指南里,你会领会到面试的概略、面试获得胜利的六大步调,以及我在察看数据构造和算法时所考虑的方面。那篇指南无法确保你找到工做,但它能搀扶帮助你尽更大可能给面试官留下一个好印象。
声明:本文中的看点完全出自小我视角,与我目前或者以前的雇主没有关系。
面试过程
本节概述了硅谷公司的面试过程,仅仅是个情状介绍,各人能够跳过往往后看。
除了间接申请面试以外,一般说来,还有两种路子来获得面试的时机:由如今的雇主选举,或者通过LinkedIn。固然前者会快一些、更尊崇一些,但后者很可能是大部门应聘者所走的途径。事实上,天天都有无数的雇用人员趴在LinkedIn上,他们独一的工做就是觅觅和接触有可能换工做的员工,所以必然要包管本身的信息是最新的,并且要多交人脉、多请他人来承认本身的技巧,而且要把你所具备的技巧、做过的小我项目或者对开源软件所做的奉献加到小我页面里往。
最后的接触一般是通过电子邮件停止的,然后雇用人员会给你打德律风,可能领会一下你的手艺布景。假设你的技巧和他们正在觅觅的技巧一致,他们就会安放一次德律风面试,在德律风面试时,你可能就会被要求在一份共享的在线文档里编程。那么你就会晓得,那份文档很可能没有任何代码补全和句法高亮的功用。德律风面试会持续半小时到45分钟,假设你表示不错,就会被邀请往参与现排场试。如今假设没有德律风面试、或者在德律风面试之外,你可能还得往参与一个小的编程项目。
现排场试由几次面试构成,总体味持续45分钟到一个小时。那些面试会和德律风面试十分像,只是问题会更难——不外能亲目睹到面试官几算是有所抵偿。现排场试数周之后,所有反应应该都被看过、雇用决定就会做出,招谁不招谁也就定了。假设你没拿到offer,也要大白面试是一个随机的过程,包罗命运的成分,无妨把它看做是一次进修的履历。可能你还会想起布莱恩·阿克顿(BrianActon)面试Facebook和Twitter不成、后来成为WhatsApp结合开创人的故事。
理论上讲,用哪种编程语言其实不重要,但你面试需要用某种特定语言来完成的工做时除外,好比iPhone开发者或者前端开发者。我强烈定见你用正在面试的公司所利用的一种编程语言来编程(以及操练面试问题)。
面试获得胜利的六个步调
编程面试的目标,是为了确定你的编程程度有多高。一般来说,你将被要求用编程来完成一个功用或者办法,但有时候,你会需要编纂一个类的定义,或者设想一系列相关的代码模块。在任何一种情状下,你都要有条不紊地处理问题,并遵照以下六个步调:
1.起首,要确保你理解了面试官的问题。许多问题都是有意措辞迷糊或者含糊其词,那个时候你能够请面试官把问题说清晰,从而确保你实正答复面试官的问题。你的发问同时还有一个益处,就是它能给你本身一些时间,让你的脑子转起来。
2.用一到两个例子来确定问题的限造前提和要求(在现排场试时在白板上完成那个过程,在德律风面试时在条记本上完成)。测验考试用中等规模的例子,以便笼盖到一些特殊情状。假设你能想到可能相关的表格,就把它画出来。事实上,把你想到的任何工具都写下来是会有搀扶帮助的,因为它能为你供给一个视觉锚点,从而让你在走欠亨时或者根究过程中随时返回某一个点。
3.把话说清晰,那可能是最重要的一步。要试着让面试尽可能有更多的互动,面试官不晓得你在想什么,而让他们参与到你的根究过程里,会让她给你一些有用的提醒,避免你偏向错误的标的目的。你的目标就是要先和面试官确证你的谜底,然后再往写代码,并且你考虑谜底越清晰、越高效,你得到的立即反应也就越好。
4.通过利用以下身手来找到谜底:回想一下你碰着的类似问题,再想想它们是若何被处理的,测验考试各类差别的算法(分治算法、贪婪算法、递回、排序,等等),把问题合成成更小的、可处置的小问题(如许你就能得到响应部门的分数),最初再通览一遍你列出的数据构造,因为有时候,只要想到了准确的数据构造,就能给出准确的谜底。
5.当你向面试官问清晰了问题、并向她阐了然你的谜底之后,就能够起头写代码了。要记住,在共享文档里写代码的时候,你能够复造粘贴、写评论,并且能回过甚来完成骨架算法和功用。但在白板上写代码就纷歧样了,它需要你的思维很清醒,并且需要你具备治理白板空间的技巧。假设足够幸运的话,如今当你起头在白板左上角动笔的时候,应该十分大白你要写些什么工具,并且你要确保在你写谜底的时候,没有盖住面试官的视线。花点儿时间把代码写得紧凑而美看一点儿,因为你的代码也会是面试反应的一部门。在你写代码的时候,要高声阐明你在写什么,那会让你的面试官更随便地跟上你的构想。
6.最初,用差别的例子和特殊案例验证一下你的代码,而且要一行一行地过。那会展现你的根究过程,让你查抄出小错误,并告诉面试官你的办法是可行的。假设你想得到额外加分的话,以至能够把单位测试的代码写下来!最初再和面试官聊一下你的谜底在空间和时间操纵方面的冗杂性,然后完毕整排场试。
德律风面试中提醒出的问题
德律风面试值得特殊一提,因为那是大大都人失利的处所。之所以会如许,部门原因在于德律风面试是雇用过程中第一道实正的关卡,但也有一部门原因在于,那种形式随便形成沟通的错误,并且欠缺可视化线索,所以德律风面试是特殊严格的。
德律风面试有两大障碍。第一大障碍是,在德律风面试的一起头,两边都能看到的独一的工具就是一个空白的共享文档。那会让面试者倾向于过度抵偿非语言沟通的缺失,从而着匆忙慌地在屏幕长进行沟通。令人遗憾的是,那么做很少会有好成果。所以燃眉之急并非往存眷阿谁正在盯着你的空白文档,而是要起首理解和评估问题(也就是完成上述六个步调中的前四个),同时通过尽可能地沉浸到面试中来填补现实存在感的缺失(要记住,德律风的另一头是一位能够很随便就被此外工作[好比查看邮件]分心的面试官)。
德律风面试的第二大障碍,就是要同时在电脑上打字和在德律风上聊天的后勤保障问题。你没必要一只手敲代码、一只手打德律风,也没必要把德律风调到扬声器形式,我定见你用电脑上的Google Hangouts接面试德律风(你得有一个GoogleVoice号码,并且得在面试前测试一下)。你还能够用耳麦或者耳机来进一步降低欠好的领受效果、进步沟通量量。
算法+数据构造=法式
假设你正在根究为什么软件工程的面试和日常编程纷歧样,那你可能有兴致读一下Quora上的那条答复。最底子的原因在于:面试是为了测试你在计算机手艺方面的根底,所以会十分侧重算法和数据构造,因而你可能需要操练一些面试问题,从而让本身具备处理面试问题的心态。
从短期来看,你所能做的更好的筹办工做就是买一块白板,并通读一遍《法式员面试金典》(Cracking The Code Interview),里面都是很好的定见,并且里面的许多面试问题和谜底会搀扶帮助你确定问题所在,并婚配好答复形式。请参阅本指南最初列出的常用面试问题。
当然了,久远来看,我们城市死掉,所以我会把工作搞简单,说一些你绝对应该复习一下的关键概念。
数组/字符串
大部门数组和字符串是可互换的,事实上,你碰着的大部门字符串处置的问题,都能够在理解数组的根底上得到处理。记住那一点之后,你应该懂得若何遍历数组,晓得若何拜候、转换和互换此中的每一个元素,并且要懂得若何对它们停止各类差别的聚集运算。和其他算法比拟,二分法检索(Binary search)可能会更多地成为面试问题的核心内容(假设你曾经碰着过有分类数组的问题,那么二分法检索有可能应该是你谜底的一部门),你绝对必需晓得若何利用它。
排序
和数组密切相关的,是排序算法。你不大可能会被要求反复利用一个排序算法,但很可能你至少晓得排序是若何在O(nlogn)的时间里完成的就行。不外你应该可能晓得回并排序(merge sort)或者快速排序(quicksort)和基数排序(radix sort)的施行细节。
动态数组/可增数组
动态数组能够按需从头调整本身的大小,同时照旧供给分时平摊的持续时间拜候。一种典型的做法是,当在一个全摆列数组中增加一个元素的时候,会构成一个新的、更大的数组,而旧数组中的元素也会被复造到新数组里。你应该在面试时做到完成一个动态数组。
假设你拿到一个非数组类问题,但你在答题中需要用到像数组构造如许的数组,无妨少给本身惹费事,间接用动态数组吧。
哈希映射/哈希表/词典/哈希聚集
哈希表(Hash tables)是编程时的瑞士军刀,良多差别类型的问题(查抄存在、计算频次、排序,等等)都能用哈希表来完美处理。它几乎必定会呈现在你的面试中,而你应该理解它的原理(哈希功用的角色、抵触若何处理、什么时候要调整大小、为什么)以及若何运用它们。
链表
链表问题在C和C++的面试中最常见,因为它们是弄清晰应聘者能否理解指针的一种简单的办法。不外那个点太初级、太根底了,所以不管用哪种语言,你都应该晓得该若何从零做起利用它们。并且因为大部门链表问题不外是与人所周知的遍历还有删除和插进相关的问题的变体,所以链表问题筹办起来很随便,你没有理由拿不到那部门分数。
许多链表问题中城市用到一个小身手,那就是慢速/快速指针手艺。它的简单版含义如下:利用两个指针迭代生成一个列表,此中一个指针在另一个指针的前面。快速形式下的指针可能会是一个位于前面的固定命值(它有助于确定列表有无轮回,或者找到列表中的第k个元素),或者也可能会跳过慢速指针颠末的多个结点(打个例如,假设快速指针的速度是慢速指针的两倍,那么当它抵达列表末尾时,慢速指针将会位于列表的中间)。
请重视,当面试官谈到链表时,他们经常指的是单链表,但你无论若何都应该问清晰。
栈/队列
栈和队列一般会是你用来解题的数据构造的一部门。你应该晓得若何用链表和数组两种体例来实现它们。
加练两道题:操纵两个队列实现一个栈,以及操纵两个栈来实现一个队列。
树/二叉树/二叉搜索树(BST)/字典树/堆
你可能不会天天都见到树和图,但你很可能会在面试时碰着它们,所以你要彻底地看一下那些数据构造。
树最一般的定义,是和其他结点没有或者有一个以上关系的结点的聚集,但在理论中,当面试官说“树”的时候,他们指的是一种喊二叉树的工具。二叉树是一种树的类型,它的每个结点都至多有两个子树,一般被称为左子树和右子树。
你不该该把二叉树和二叉搜索树稠浊起来,后者是一种特殊的二叉树,它的左子树结点上的值都比父结点小,而右子树结点上的值都比父结点大或者相等。二叉搜索树的长处是,假设树的构造相对平稳(向面试官问清晰那个问题),那么查找、插进和删除就能够在O(log n)的时间里完成。二叉搜索树的其他重要属性,就是你跟着所有的左子树走,就能得到那个树上最小的元素,而跟着所有的右子树走,就能得到那个树上更大的元素。
请重视,是有办法让树不断连结平稳的,最常用的办法就是红黑树和AVL树。我不会往弄清晰它详细实现的细节,只要晓得有那些数据构造就行。
不外你绝对必需晓得遍历树(tree traversal)算法:广度优先搜索(breadth-first-search)、深度优先搜索(depth-first-search),以及中序遍历、后序遍历和前序遍历之间的区别。
以下是在Java实现中序遍历的例子,它能够打印出一个树的所有值(前序遍历和后序遍历几乎和那个一样):
void inOrderTraversal(Node
root) { if (root == null) return; inOrderTraversal(root.getLeft()); // System.out.println(root.getValue()); inOrderTraversal(root.getRight()); }
字典树(trie,读“tree”)经常被用在字符串问题里,它是一个n元树,除了根结点以外的每个结点都代表一个字符或者部门或完全的单词,并且沿着树的每一条途径都代表一个单词。现实上它实的没有听起来那么冗杂,只要读一下维基百科上的页面、领会该若何构建一个字典树以及若何查询此中的数值就行。请重视,你能够通过前序遍历输出字典树中的所有键。做为一个操练,你能够想一想本身会若何操纵字典树实现主动完胜利能。
最初是堆(heaps),它也被称为优先队列,是你应该领会的最初一种数据构造。它们凡是都是称心堆属性的二叉树:每个结点的子树的值都比结点自己的值小,或者与它相等。所以根结点的值老是更大的,也就是说你总能找到更大值,但代价就是觅觅其他任何一个值所需的时间都是O(n)。插进和删除所需的时间照旧是O(logn)。
有向图/无向图/加权图
和树一样,图也是由带子集的结点构成的,但和树纷歧样的处所在于,那些结点能够有多个父结点,所以可能会构成自环(loop)或者圈(cycle)。除了链接——也被称做边(edges)——之外,两个结点之间可能地有比指针更多的信息,并且可能会有值和权重。边有标的目的的图被称为有向图,而只要双向指针的图被称为无向图。边上有权重的图被称为加权图。
有三种办法来表达图,但你只要搞清晰邻接矩阵(adjacency matrices)和邻接表(adjacency lists)就行了。你应该领会它们计算的冗杂水平、它们需要折衷的处所,以及若何在现实的代码中实现它们。用哪种办法取决于你有的图的类型,好比毗连完全的简单图可能用邻接矩阵来实现更好,而稀少一些的图则可能用邻接表来表达更好。
请重视,假设你是在实现加权图,很可能需要定义一个Edge类。
图论是一个十分广泛的话题,所以很难晓得一小我应该为一排场试往熟悉几种图论算法,所以我只是列出了我认为能够笼盖90%图论问题的内容:你绝对必需晓得该若何遍历一个图(深度优先或者广度优先),以及若何做拓扑排序(topological sorting),你应该晓得若何实现迪杰斯特拉(Dijkstra)的最短途径算法(那里有一个造造精巧的视频阐了然那一算法),同时也要晓得若何实现普里姆(Prim’s)算法。最初,假设你还晓得若何实现A*搜索算法(A*searchalgorithm),那就更好了。
其他数据构造
利用以上数据构造,你就可能处理绝大大都问题了,但也请虽然在那个部门下留言,为其他读者选举其他数据构造。
位操做
要想处置位元,你必需先得晓得在二进造补码(two’s complement)标识表记标帜内部,数字是若何表达的——二进造补码和无格局二进造标识表记标帜是一样的,只是负数要“停止位元翻转之后再加1”。好比要想得到数字-1,你要从用8位二进造整数表达是00000001的1起头。对每一个位元停止翻转之后的成果是11111110,再加上1就是11111111,也就成了二进造补码中的-1。
左移位运算符“”会把位元移向右边,用0来补上移走之后的空位。
右移位运算符“”会把一个位形式向右移,但当向右挪动负数时,它的感化在差别编程语言中也纷歧样,在Java中,右移位会用符号扩大的办法,用1来填充负数中的空位。
逻辑右移位运算符“”是Java和Javascript中独有的,无论数值是几,它都用0来填充空位。
设置某一位:能够用按位或运算符(|)。
num |= 1 x; //那行代码将会设置位元x
肃清某一位:能够用按位与运算符(),而且用取反运算符(~)来屏障所有你不想肃清的位元。
num = ~(1 x); //那会肃清位元x
肃清不断到i的所有有效位元:
num = (1 (i + 1)) -1;
切换某一位元:能够用按位异或运算符(^)
num ^= 1 x; //那会切换位元x
获得一个位元:对你想查抄的位元用按位与
bit = num (1 x);
设想形式/面向对象编程
和面向对象编程相关的问题,一般会涉及到设想相关类里的集,以便查验你对面向对象编程的熟悉水平,并领会你是若何架构代码的。你能够利用界面和/或笼统的类来阐明,并记住用单例形式(Singleton)、工场办法形式(Factory)和战略形式(Strategy)来处理那类问题,在编写高雅而可庇护的代码方面,它们能对你有长久的助益。
编程应该晓得的工作
要晓得若何用你正在利用的编程语言来读取和写进文件,而且要晓得若何生成随机数。
数学
你并非在面试数学相关的职位,但考虑到我们被计数和丈量的问题所包抄,所以有一些数学概念也成了编程面试时存眷的工具,比力重要的有量数、进造转换(base conversions)和一些根本的组合数学。
关于量数,要可能晓得为什么它们很重要,而且要晓得每一个数都能够被合成成量数的和。你还得晓得若何实现埃拉托斯特尼筛法(sieve of Eratosthenes)。
关于根本的组合数学,你得晓得摆列和组合。
摆列是对一个聚集中的数根据必然的次序或者挨次停止整理。好比关于聚集{1,2,3},就有6种摆列的体例,也就是(1,2,3)、(1,3,2)、(2,1,3)、(2,3,1)、(3,1,2)和(3,2,1)。n个差别数字的摆列体例一共有n!种。
还有一种摆列喊部门摆列,也就是从n个数字的聚集中取出k个差别的元素,然后再停止排序。那种摆列能够用下面的公式来表达:
部门摆列公式
组合则是从一个组里抉择成员的一种办法,因而抉择的挨次其实不重要。好比一手牌能够被描述成是从52张一摞的牌堆(n=52)中选出5张构成一组(k=5)。从有n个元素的聚集中挑出k个元素,当kn时,不存在响应的组合,不然那k个元素的组合的数量能够用下面的公式来表达:
当k=n时,从有n个元素的聚集中挑出k个元素的组合形式数量的一般公式。
并发
并提问题在面试中其实不常见,但也确实有过,所以你必定不想到时候毫无筹办,那就再往看一下若何生成线程、利用同步以及锁定对共享资本的拜候,并理解会招致死锁(deadlocks)的几种情状。筹办那个话题有一个好办法,那就是往做出来一个你最喜欢的数据构造的同步版本。
面试时的行为举行
做些功课,领会一下要面试的公司,领会一下你本身,以及为什么你要往那家公司。要理解公司在做的事、你的新工做涉及哪些工具,以及它最让你冲动的处所是什么。换工做是件大事,所以要认实看待它,提早做些研究。
连结积极心态。连结一个好的情感,要浅笑,不要议论和你如今或者之前的工做有关的负面信息,当描述挑战的时候,要连结乐看的腔调,并强调你从中学到的积极的工具。
本条是前一条里说的不要向面试官传递负面信息的一定成果。一些面试官会问你如今觉得若何,万万别说你之前受不了某一位或两位面试官,必然要说所有工作都十分好。
要连结激情!要让你的冲动之情闪亮全场,并展现出你对软件开发、手艺息争决严重问题的热情。
要问问题。要实正对你的面试官天天都在做什么抱有实正的兴致,问问他们工做中碰着的机遇与挑战,提早筹办几个程式化的问题,展现一下你对公司和那个职位的兴致。不外无论你做什么,都别问对方“你觉得若何”。起首,你很可能会收到同样程式化的答复,其次,把面试你的人摆在那样一个位置上,也不是什么好主意。
连结亲热感,并构成闭环。当你完毕面试之后,给雇用你的人发一句简短的感激语,让他们晓得你对此次面试的觉得。
回想你学到的工具。无论成果若何,你都能学到一些工具——能够是常识上的某个缺失,也能够是新的面试问题——所以要做自我深思,从本身的履历中进修。
祝列位职场和面试好运!
IT优就业。