【转自一亩三分田】谈谈面试官在面试coding题目时的考察终点与心理活动html
本人简介: 曾经微软dev, 35+, 10年经验, 有FLG offer. 去年加入一个start up 公司, 最近前景不明, 在犹豫要不要去个稳定点的大公司。 我从sde开始面试其余人, 到如今估计面试过100+人次的面试和debrief。 我面过coding, problem solving, design, behavior. 本帖子只谈论纯粹coding, 视状况讨论要不要再开帖子讨论其余方面。
本文涉及下面几个问题:
1) 我刷过这个题目, 还要不要假装
2) 我以为这题很简单, 可是不知道为何就挂了
3) 我以为面试官不是很友好, 没提示
4) 我必定要bug free才能被录取吗
5) leet code的hard问题真的会被问到吗? 考起来有什么意义?
咱们从一个很是经典的, 你们可能都刷过的题目开始。 序列化/反序列化 二叉树。先说个背景, 能面到我这里的, 基本须要面试者有3-5年的面试经验。 作为应聘任何微软或者flg的高级dev (63 and above, T4/E4 and above), 面试官其实都是假设你刷过很多题目的。 我假设你刷过这个题目, 因此我并不关心你写的到底有多快,写的是否是彻底bug free, 我更关心的是你作事的方式和沟通问题的能力。 具体请看下面。
1. 提出问题, 请序列化/反序列化二叉树。
什么? 面试者不知道什么是序列化, 反序列化? 那我就问个多线程爬虫, timing LRU 一类的。 若是多线程, 锁也不会, 那说明这个面试者的项目经验很不足。 为了和其余有经验的人相match, 每每我会给一个很open的问题, 或者一个很难的hard coding (取决于他已经被考察了哪一个方面). 我我的以为不多有面试官上来会考你 very hard coding question, 只是当某个面试者与其余面试人比显得至关缺乏项目经验, 那他除非能在聪明敏捷或者下苦功方面有突出表现, 不然很难击败其余候选人。
2. 交流阶段
若是面试者立刻开始写程序, 或者立刻给出他的想法, 我会以为面试者太过于着急了。 在实际项目中, 你很熟悉的地方可能成为项目中的滑铁卢, 由于你熟悉的地方可能有变化, 可能有个big change你不知道, 可能很快你熟悉的api就不工做了。 你老是要有很好的沟通能力, 确保你们知道你在作什么, 及早的发现你的错误。 在code review甚至是test 阶段被人发现问题对项目来讲就是个灾难。
我指望面试者可以在这个阶段提出一些问题, 例如,有什么限制条件吗? 二叉树的value是什么类型? 这个api谁来使用, 内部的仍是public的? 这个api更注重speed仍是space? 我须要多线程吗? 若是面试者没问任何问题立刻开始照着leetcode的signature开始coding, 甚至class 名字也叫solution(不少人), 我会以为面试者作事的方式不够成熟。 可能之后工做中会很毛躁, 须要人来指导。
3. 不管你提出的建议是什么, 例如你说你以为speed更重要, 我可能会说我更期待space. 这样作是避免陷入你最熟悉的套路。 假设我说, 我更须要序列化以后的空间占用最小。 这时候通常的候选人不会刷到这么深, 开始思考。
若是候选人根本没有办法优化空间, 那我会认为他give up too early. 我但愿候选人能安静的思考, 提出几种方案, 哪怕方案不成立。
若是候选人提出过多的方案, 没有问help, 这些方案也不工做, 我就认为候选人沟通有问题, 没法把握好度。
举个leetcode的例子来讲明问题的深刻, leetcode的序列化格式中, ','是必要的吗? ‘[’是必要的吗? 有没有办法用byte直接序列化? byte还能变长吗? base64是什么? zip会有帮助吗?
4. 候选人选定方案后, 我但愿他能和我沟通, 看看是否是在有限时间内可以写完。 项目中, 不少时候谁都知道什么design是正确的, 什么是bad smell, 最聪明的人不是能作出最好design的, 而是在有限时间内能给出你们都能接受的solution的人。 若是空间优化很是好, 可是代码将超级复杂, 没法写完, 那么面试者应该及时和我交流。 我也会偶尔提醒一下这样能不能在40分钟内写完。 若是面试者坚持, 我不会坚持, 我会看他是否是能写完。 这就是either strong hire or fail.
5. 候选人可能这时候说太复杂了, 咱们简化一下, 简化到他熟悉的, 刷过的coding.
6. coding 开始
到这一步, 若是你作了2,3,4,5中的大部分, 而且code看起来彷佛是work的, 没有什么致命的问题,我不会纠结于好比正负数, nullpointer, int.min, coding是否是整洁一类的无聊问题。 通常就开始7. 若是你2,3,4,5都skip, 那么通常我就但愿你bug free, 不然你没办法和其余候选者作比较。每每bug free又要求你code组织很好, 不然谁都很难一眼看出你有没有问题。
7. follow up
还有什么能改进的吗? 这是考察面试者的知识面, 也看你是否是耐心。 不少时候, 不少面试者作出题目高兴的忘乎所以, 到这里就开始语无伦次的乱说, 这不会影响到是否是hire, 可是可能会影响是否是strong hire, 也可能影响到你的level.
举例子: 我以为还须要写点java doc啊,unit test, regression test, performance tuning, benchmarking, A/B testing, 等等。
总结: 若是你能想到1-7中的全部点, 谁会在意你是否是刷过这个题目? 即便你刷过这个题目, 我也十分肯定你刷的比别人好不少, 你就是我心中想要的那个同事。 反之, 若是你只作到了6#, 可是别人作了1,2,3,4,5,6,7, 那你又怎么能面试成功呢?java
前几天写了个关于面试官心理活动和侧重点的帖子, 见 谈谈面试官在面试coding题目时的考察终点与心理活动, 求大米, 首先感谢你们的捧场与大米, 也请你们原谅个人一些错别字与语无伦次(为了快速求大米写的粗糙了一点), 反应超出个人预期。 也让我有了动力接着写这一篇帖子。
在上一篇帖子中提到了coding的通常步骤与考察点, 在开贴讨论design,behavior, culture fit前, 继续深刻的讨论一下coding的考察范围, 也以此作为对一些同窗, 特别是new grad的问题的统一回复。我就不排版和检查拼写了, 你们继续凑合读。
coding 种类与应对策略
大体上, 面试官在开始面试前, 会收到一封email, 里面回大体说明每一个人须要侧重于考察面试者的哪一个方面。 对于coding来讲, 通常有三类问题, 每一个面试官会被分配到一类问题。
1. solid coding
这类问题说白了, 谁都知道怎么作, 纯粹就是考察coding是否是扎实, 平时本身写code多很少, 能不能快速的把本身的idea转化为code。 对于面试者来讲属于必考种类, new grad 通常会有两轮甚至三轮这样的题目, 有不少工做经验的人可能就只有1轮了。 这类题目不过关, 极可能电面死掉或者前几轮忽然死亡。
solid coding又通常能够分红两个小类:
1.1 考察你对算法的基本理解以及边界条件的运用, 好比findkth largest integer, search in rotate array, bit manipulation 等等。
1.2 考察你对基本数据结构以及复杂度的理解。 好比binary search tree, linkedlist vs array, stack, tree dfs, tree bfs 等等。
按难度来分, easy的好比3 sum, tree level order iterator. medium 难度的好比 reverse linked list from index m to index n, course schedule,string multiplication, hard 难度的好比valid number, 复杂的calculator等。
应对策略:
1.1 类型, 若是是简单和medium的没得说了, 就是但愿你又快又好, 除了勤奋和熟练, 没有什么好策略。 对于像merge sort, partition这类的算法, 若是7-8分钟还写不出bug free我估计就没戏了。easy问题请多多注意边界条件, int 溢出, nullpointer, 负数, 非法输入等。
hard 1.1的请参考1.3
1.2 类型, 简单和medium请在写代码前多阐明复杂度, 这类数据结构的问题每每也能够在coding前画图来表示运行状态, 图画的清楚也是个重要的加分项。 hard请参考1.3
1.3 hard类型的coding题目. 这每每是考察你的solid coding的能力, 即我在前文中提到的, 你作事的方式和你思考问题的方法。 即给你一个coding任务, 你如何从白板开始, 一步步的作出bug free的程序。 这类问题的过程重于结果。 好比valid number, 你能确保每实现一个模块, 都没有regressgion, 都没有bug, 比你一会儿实现全部的feature可是有不少bug 要好不少。 通常来讲面试官看你是否可以一步步的分隔出小的coding模块(method), 你如何设计test case, 你如何可以确保这些test case能cover全部的scenario, 你是否是和面试官提早作了足够的沟通而且限定了coding范围。 从这个角度来讲, valid number实际上是个很不错的solid coding面试题。 限于篇幅, 我就不展开来讲了。
2. problem resolving
这类问题对于new grad是关键, 也是能帮你differentiate的关键。 说白了, 计算机并非只有算法,咱们还须要数据库, 操做系统, 网络, 安全等方面的知识。 new grad这些方面要弱一些, 因此面试者但愿new grad能展示出思惟敏捷, 多思考, 快速反应的能力。 problem resolving就为了考察这个能力而诞生的。
problem resolving也能够分红四个小类型。
2.1 API design. 这类问题是为了更深刻的考察你对数据结构的理解与运用。 例如LRU cache, insert delete getRandom ALL O(1) , design twitter等等。
2.2 Abstraction. 这类问题是考察你能不能把一个相对抽象的问题规约到你熟悉的问题上面。 好比skyline problem, int stream find median, cleaning robot等等。
2.3 计算机小程序, 例如thread pool, 爬虫,日志merge等, random generator等。
2.4 dynamic programming问题。 这类问题有点像solid problem resolving. 主要考察你是否是有systemmatic的方法来下降一个brute force程序的复杂度
这类问题通常都不是很easy的问题, 根据面试官心情, 可能走的很深很难。 也可能最后演变成bar raiser.
应对策略:
2.1 主要考察你对数据结构的深层次认识。 首先请同时确保你理解了题目的意思, 最好能问清点条件 例如immutable array max subarray sum, 那数组未来会变吗?问清这类的问题有助于你写代码前作好重构和测试的准备。 其次, 若是你能证实你选择的算法的复杂度, 甚至证实这就是最佳复杂度, 那是一个大大的加分项, 若是不能, 至少你也问问面试官是否是已经满意了再开始写代码。
2.2 这个我本身也头疼, 说实话若是第一次碰见了skyline, 我也不知道能不能搞定。 你们有好办法请回复有什么好办法能系统化的解决这类的问题, 我我的以为不少时候靠灵光一闪。
2.3 这类问题主要看你平时积累, 也是一大类不能经过leetcode练习的问题。临时抱佛脚的话, 我我的推荐java concurrency in practice这本书。
2.4 动态规划, 我不知道为何不少人惧怕动态规划。 面试中的动态规划大体分为单向递归(首或者尾), O(n2)或者O(n3) 距离递归, O(mn)递归,有限定条件的NP (背包)。 每种类型听几节课, 懂了基本原理便可。 至于贪心和带状态的dp(走道铺砖)一类的dp, 至少我没在面试中遇到过, 由于很难临时造出一道这样的题目, 面试官通常也没这个能力和时间来思考题目是否是严谨。 贪心准备下加油站, 迪杰斯特拉, 最小生成树就足够了。
3. bar raiser
这类的问题只有当onsite应聘者的数量远远大于head count的时候, 或者你前几轮明显超出了电面时对你的定位才会发生。 其目的是帮助公司选择最优秀的人。 对应聘者来讲, 坏消息是要度过痛苦一小时, 好消息是你能充分了解这公司厉害的人有多厉害, 能充分展现你的能力, 甚至被越级录取也不是不可能。
bar raiser也是三小类。 c++
较难的hard题,最好在完全理解答案的基础上背题。面试官比较看重的是获得这个解法的过程。
咱们来以skyline的表演为例,抛砖引玉一下~
题目要求的是建筑的剪影,能够抽象为每一个固定横坐标上的最高点(划重点:提取问题核心)。所以这个解法能够分红两部分:
(1)如何把input转换为线性,从而抽象成扫描线问题(甩名词:sweep line)
(2)扫描线的具体实现
第一部分,若是想要简单扫一遍,数据必须是按x轴排序的。假设咱们 start_x 来对 building 排序,则end_x仍然是无序的,这样很差。(此时演技爆棚一拍脑壳想到)咱们只须要知道skyline的线段是在哪里开始的,所以在building高度发生变化的X位置进行处理便可。building的开始和结束都算是高度变化,所以能够把 start 和 end 拆开处理,只须要标记 X 位置上的高度数据以及这个高度是开始仍是结束。
至于每一个X位置数据的具体结构,能够用一个tuple(int h 高度,bool start 表示是开始仍是结束),也能够像高票解法同样用正数表明开始、负数表明结束。能够和面试官阐明。
第二部分,主要是如何维持一个高度的queue。
阐明在扫描过程当中须要三个操做,插入(遇到start),删除(遇到end),获取最大值(高度更新),所以可能有:
1. 由于要取最大值嘛,因此很明显咱们试试heap,插入O(logn),max O(1),可是删除是O(n),不太好,咱们试试别的;
2. balanced bst (c++ ordered map以及java treemap),全场O(logn),统统O(logn);
3. 有没有可能优化方法1呢?能够用 hashmap + heap的方式来实现,O(logn) insert, O(logn) remove, O(1) get_max。
第一部分稍微举例说明了一下如何展现思路。
第二部分我认为是装逼重点。能写方法3,就先列出1和2,指出他们的不足,而后提出3。若是懒得实现3,先提出1,再提出2,指出红黑树的时间优于heap,在面试官看来也是对数据结构足够熟练的应用了。
最后记得提出edge case,好比两个building高度相同怎么办(伪装思考一下)若是先push start,再pop end,就不会有高度变化的问题了嘛,因此咱们重写compare函数的时候注意一下就好了。
以上整个过程,在表演不崩的状况下用5-8分钟来解释,我认为都是能够的。
两年没刷题了,具体细节可能记得不太清楚。最近刚开始当面试官,在演技方面给你们举个栗子🌰。对于这种candidate,即便对方多是在表演,若是可以把问题肢解得这么清楚、把多种实现细节的trade-off分析得这么明白,我也会给一个pass的。
(皮完就跑 #滑稽#
补充内容 (2018-7-29 05:14):
解释思路的时间扩展到10+分钟应该也能够吧,诸位要不要试试mock一下计个时?咱们统计一下(笑)
总之只要思路连贯,有理有据使人信服,就不会演崩。但必定要有develop思路的过程,这也能体现对解法的充分理解git
写一点刷题感想github
前先后后刷题也一年了,不少感想。因此想总结出来。我也不知道本身说的对不对,因此正好和你们交流,相互学习。
最核心的三条:
1. 想刷的好没别的,惟手熟尔。
刷题跟高考数学本质如出一辙。想一想过去高中三年啥事儿都不作,每天作卷子,看到题就大概知道怎么作。而现在由于生活忙碌,各类事情distraction,致使刷题可能变得时间不够。再看看leetcode contest那些20分钟作完四道题的牛人,不少都是有ACM竞赛背景的。固然或许他们的确天资过人,但我更相信他们是从小开始训练coding,见多识广,经验丰富,submission上万遍,付出无数努力才能维持如此高的应试水平的。
另外,对于全部leetcode mediun题甚至一些hard题,也是要求你在半个小时甚至更短期内作出来,不是要你花几个月几年时间作调研写报告或者作research探究人类未知,因此内容自己应该是很简洁的一个小问题(固然简洁不表明简单)。因此刷不出来?why?就一句话:刷少了。知识点不够熟,或者XX算法没见过,或者这种题型很陌生。不会的东西均可以在网上找到答案/资料/训练,而不像作research你面对的是unknown的东西须要花费巨大精力去不断尝试和研究;因此不会的就学习,缺乏的就补课,每学一点,就进步一点。很是公平。
因此主要仍是本身努力的不够。这是我最大的感觉。
2. 最好作到不间断。
上面说的是刷题本质,回答的是what的问题。如今说一下how的问题。
个人一个感想就是,从应试记忆的角度来讲,必定要不间断的刷题,时刻保持手感。中间若是停掉一个月或者几个月,再pickup起来的成本就会很大。这也是我本身的一个重大教训,我本身毅力不够。每每别的事情一忙碌,就完全把刷题抛在脑后了。过了一个月再回来狂刷。但我慢慢发现这个方式并很差,那些刷题很牛的人,他们必定是细水长流的,天天刷,哪怕天天只submit一次也能够。
固然说的容易,作起来难。就是毅力。
3. 不停的总结套路+题型。。
若是说刷题有啥技巧,最核心的我以为就是要不停的总结套路和题型。固然还没刷到200题的就不要care这个,先把量作到足够多才有必要总结。仍是那个古老的规律:好记性不如烂笔头。以前说了,刷题本质就是努力,而努力的核心就是不停刷;如何高效的不停刷呢?就是作总结笔记。并且必定是参考其余人笔记后,作出的最适合本身的那个笔记,宛如本身的指纹,全世界独一份属于你的。好比,DFS/BFS画个图写个pseudo code总结下。而后有的题为啥BFS比DFS强?拿一个题作例子总结一下。有的题是DFS/BFS+union find;有的题是DFS/BFS+DP,分别总结下。backtracking里各类subset,permutation,combination总结一下看看他们的区别。Comparator怎么写?忘记了?赶忙总结个模板。相似的,2D array/priorityqueue如何sort? 。。。
无论任何大模板,仍是小细节,都要作笔记。无论你用evernote,github,gitbook仍是什么别的。
除了少数技巧特殊的题目,其余全部题目必定掌握核心灵魂,而不是死记硬背。我过去就犯过这种错误。已经两个月没刷题了,忽然来个面试,慌了,因此赶忙把code背一背寄但愿碰到原题。最后面试的时候一塌糊涂。而我那时候尚未很认真的作总结。因此有一份刷题总结在手,做为面试前复习的精华,就不怕任何突如其来的面试了。
因此刷来刷去,刷出来的就是套路。如何掌握这些套路?努力呗。
另外还两小点。
第一就是我以为如今题型核心就是DFS/BFS/Tree/Backtracking/UF以及延伸出的一些东西,这些都是一条绳上的蚂蚱(说的不对请指正)。固然还有一个点就是DP。 可是过于难的DP实在是想不出来。因此我不知道DP这个东西也是能够经过不停努力掌握的吗?
第二就是,面试的时候和leetcode刷题仍是很不一样的。lc刷习惯了会产生对那种环境的依赖感。而实际面试可能要你本身写main function;或者白板面试。这些都是要额外训练的。面试