Thursday, May 22, 2014

[Interview] Techinical Code Interview 流程总结



面试经验也积累一些了,近期学不进去就写写总结。

Technical Interview除了题目是否作对,感觉其他的也非常重要,思路和communication.
  • Communication. 贯穿面试,体现沟通交流能力
  • Thought. 思路,体现problem - solving 的能力
  • Coding. 编程能力, 是否能将solution转换成program. 


所以整个面试结果三部分组成: 
感觉真的是综合考察,很多题目哪怕作对了,都会挂,还有一些题目虽然没有bug free,但是经过提示修正,或者思路对了,有一些小bug,也可以过,这点感触很深。

找了一份材料,是完整的code interview的过程,应该是palantir家给面试者的,我觉得是很科学的,应该用这个套路,这种思维去不断强化,达到快速反应的能力,这是绝对是综合能力的养成。


对于刷题,越发感觉不能麻木的刷,一道题目是否真正领会思想,举一反三很重要,单靠数量,记题一点用没有,题目蕴含的思想是最重要的,我得反思,重新来过。

Before you start coding

  • Make sure you understand the problem. Don’t hesitate to ask questions. Specifically, if any of the problem requirements seem loosely defined or otherwise unclear, ask your interviewer to make things more concrete. There is no penalty for asking for clarifications, and you don’t want to miss a key requirement or proceed on unfounded assumptions.

题目没弄明白绝对是大忌啊,记得之前说Amazon面试,面试时候不确认题目扣10%还是多少来着。

我这两天接连犯这个错误,Symmetric Difference,还有找零钱方案数or所有方案 都没完全确认就开始动手了,还有个大忌,不要想当然这是Leetcode或者CC150的题目,往上套,很多时候没读清楚,其实不是个题目,一定注意。

  • Work through simple examples. This can be useful both before you begin and after you’ve finished coding. Working through simple examples before coding can give you additional clarity on the nature of the problem — it may help you notice additional cases or patterns in the problem that you would otherwise have missed had you been thinking more abstractly.
如果没弄明白题目的话,实例最清晰明了,而且会帮助考虑一些corner case. 即便是弄明白了,自己也可以写一个例子跟面试官确认一些,这样也不浪费时间,而且看着这个写代码也会高效一点,不过注意,这些simple example 有时候会导致我们忽略一些corner case. 总之要多注意
  • Make a plan. Be wary of jumping into code without thinking about your program’s high-level structure. You don’t have to work out every last detail (this can be difficult for more meaty problems), but you should give the matter sufficient thought. Without proper planning, you may be forced to waste your limited time reworking significant parts of your program.
对一道题目,很多时候多种解法,这步主要跟面试官描述下自己要怎么做,感觉没太多经验的或者一般的面试官就会让你直接写,一些有经验的面试官会先问问你时间复杂度之类的,确认一些solution有没有问题,或者是不是他想要的,这里能给最优解就给最优解。
  • Choose a language. At Palantir, we don’t care what languages you know as long as you have a firm grasp on the fundamentals (decomposition, object-oriented design, etc.). That said, you need to be able to communicate with your interviewer, so choose something that both of you can understand. In general, it’s easier for us if you use Java or C++, but we’ll try to accommodate other languages. If all else fails, devise your own pseudo-code. Just make sure it’s precise (i.e. not hand-wavy) and internally consistent, and explain your choices as you go.

While you’re coding

  • Think out loud. Explain your thought process to your interviewer as you code. This helps you more fully communicate your solution, and gives your interviewer an opportunity to correct misconceptions or otherwise provide high-level guidance.

我自己的做法一般是在动手前先把solution 说清楚,coding过程中尽量集中精神少沟通,不过也碰到一些情况确实需要沟通,比如一些invalid parameter的return值,还有其他的一些编程中遇到的问题,该问的就问,觉得无所谓的可以说自己假设这里应该怎么弄,也OK。

  • Break the problem down and define abstractions. One crucial skill we look for is the ability to handle complexity by breaking problems into manageable sub-problems. For anything non-trivial, you’ll want to avoid writing one giant, monolithic function. Feel free to define helper functions, helper classes, and other abstractions to reach a working solution. You can leverage design patterns or other programming idioms as well. Ideally, your solution will be well-factored and as a result easy to read, understand, and prove correct.

程序一定要简洁明了,该拆分的就拆分,这种尤其体现在ListNode这类题目,经常需要多个helper function.
  • Delay the implementation of your helper functions. (this serves a corollary to the previous point) Write out the signature, and make sure you understand the contract your helper will enforce, but don’t implement it right away. This serves a number of purposes: (1) it shows that you’re familiar with abstractions (by treating the method as an API); (2) it allows you to maintain momentum towards the overall solution; (3) it results in fewer context-switches for your brain (you can reason about each level of the call stack separately); and (4) your interviewer may grant you the implementation for free, if he or she considers it trivial.
有些题目,需要swap(), 或者List getLength(), 直接写出来函数名用就好了,因为简单明了,最后再补充helper function,时间紧的时候不写的都没关系,无所谓的. 一般都是些简单功能抽取出来
  • Don’t get caught up in trivialities. At Palantir we are much more interested in your general problem solving and coding abilities than your recall of library function names or obscure language syntax. If you can’t remember exactly how to do something in your chosen language, make something up and just explain to your interviewer that you would look up the specifics in the documentation. Likewise, if you utilize an abstraction or programming idiom which admits a trivial implementation, don’t be afraid to just write out the interface and omit the implementation so you can concentrate on more important aspects of the problem (e.g., “I’m going to use a circular buffer here with the following interface without writing out the full implementation”).
碰到过这种问题,比如 invalid input, throw new IllegalArgumentException("invalid input"). 当时记不住这个Exception名字了,其实无所谓的,还有file 做input,读文件的一些函数,当然了,对于常见的编程问题,不应该有记不住的,但是真是忘记了,不必纠结。

Once you have a solution

  • Think about edge cases. Naturally, you should strive for a solution that’s correct in all observable aspects. Sometimes there will be a flaw in the core logic of your solution, but more often your only bugs will be in how you handle edge cases. (This is true of real-world engineering as well.) Make sure your solution works on all edge cases you can think of. One way you can search for edge-case bugs is to…

在test case之前,养成写完code 检查的习惯,初步检查完大体逻辑没问题,自觉写test case. 这个需要锻炼和积累,不同题目有很多不同类型case,比如字符串的space,int处理的Integer.MAX_VALUE等,编程时候也要注意的到。

  • Step through your code. One of the best ways to check your work is to simulate how your code executes against a sample input. Take one of your earlier examples and make sure your code produces the right result. Huge caveat here: when mentally simulating how your code behaves, your brain will be tempted to project what it wants to happen rather than what actually says happen. Fight this tendency by being as literal as possible. For example, if you’re calculating a string index with code like str.length()-suffix.length(), don’t just assume you know where that index will land; actually do the math and make sure the value is what you were hoping for.

定式思维很可怕,我有好几次代码写的出问题了,比如while  list.add(A[i]) 忘记++,还有listNode 忘记next,跑test case时候还全然不知,因为思维已经模式化了,认定他会++,但是代码确没写。按文中提到的,一定要fight this tendency才可以!很关键,否则过一遍的效果微乎其微,别想当然。
  • Explain the shortcuts you took. If you skipped things for reasons of expedience that you would otherwise do in a “real world” scenario, please let us know what you did and why. For example, “If I were writing this for production use, I would check an invariant here.” Since whiteboard coding is an artificial environment, this gives us a sense for how you’ll treat code once you’re actually on the job.
很多不太professional的地方,要有合理解释。


另外补几点
1. 写完代码后Refactor 尽量体现出来,别只是说说,就想symmetric difference那个,在后面聊天的时候,要改动代码,因为已经清楚哪里有问题了,一定要改,不要只是留在那里,因为interviewer 是要要代码copy下来保留凭证的,也就是说,会有第三个人来看这份代码,显然我们没机会跟第三人解释!能refacor多少就refactor,代码写漂亮了。

2. 面试官指出bug的时候,一定要修改所有地方,记得又一次用int[] 设置Integer.MAX_VALUE做flag, 后来不用了, 这块初始化的代码没删掉(这块在class代码块中,不在method里面),我想的是我把逻辑已经改好了,我理解你意思并且改正了,你也知道我懂了,那个就放着吧,等你继续说别的。但是实际上是,他没办法容忍,或者说他可能也在帮我,因为这个代码要给别人看。 所以即便你知道了并且改正了一处,他也知道你懂了,沟通没问题了,你还是要改相关的地方。

3. 所有沟通的原则,就是,不要犟嘴,人家说啥你答应啥,有个题涉及两个数组问我time complexity,我说O(m + n), 其实就是O(n). 印度小哥问我为啥不是O(n).... 后来我俩沟通一下才说没问题,OK。可能他开始以为我不知道这是O(n).... 要让面试官尽可能的爽。



最后说说,其实公司要什么样的人,自己很清楚,是不是够聪明,面对未知有没有解决问题的能力,是不是很和善,容易沟通,还有基本的编程能力,既然我们都懂,就不应该回避一些点,应该直面这些能力的缺失,去不断提升,不断完善,我觉得自己在很多方面真的是有待提高,很多时候面试慌张,都是因为这些,还有我所谓的盲点,知道哪块不行,早TM干啥去了,非得面试前才去学么。总之,刷题容易,贯通不易,切刷且珍惜吧,对自己说句加油。

Sunday, May 18, 2014

Maximal Rectangle @LeetCode

Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and return its area.

A little harder than Largest Rectangle in Histogram.

Clone Graph @LeetCode

Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors.

OJ's undirected graph serialization:
Nodes are labeled uniquely.
We use # as a separator for each node, and , as a separator for node label and each neighbor of the node.
As an example, consider the serialized graph {0,1,2#1,2#2,2}.
The graph has a total of three nodes, and therefore contains three parts as separated by #.
  1. First node is labeled as 0. Connect node 0 to both nodes 1 and 2.
  2. Second node is labeled as 1. Connect node 1 to node 2.
  3. Third node is labeled as 2. Connect node 2 to node 2 (itself), thus forming a self-cycle.
Visually, the graph looks like the following:
       1
      / \
     /   \
    0 --- 2
         / \
         \_/


Largest Rectangle in Histogram @LeetCode

Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.
Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].
The largest rectangle is shown in the shaded area, which has area = 10 unit.
For example,
Given height = [2,1,5,6,2,3],
return 10.