虽然想过想过会再跟Google面试一次,只是没想到来的这么快。Offer非常诱人,果断接了,人生的第一次跳槽就这么突如其来,然后一瞬间敲定了。通过这次这个经历,知道了一些Google给offer的细节,所以决定再写一篇日志,同时发点题目大家随便看看。
这次就是Google HR给我打的电话,先说是随便聊聊,后来问出来说上次面试结果显示不错但是没有合适的team,问想不想再面一次...你妹啊!上次结果不错还不发offer,这是几个意思啊!跟HR聊天的时候得知,Google给Offer的过程其实有两步。首先,做面试。面试完后觉得不错,再第二步,allocate team。面试的人会写个报告,然后发给想要人的team去review。如果有team想要,直接给offer。如果觉得能力不错但没有team想要,就先不给offer,但是会留记录,过段时间再联系。所以时隔一年半就又来了一次面试。
具体面试程序基本和前一篇写的差不多。虽然上次算是new grad level的,这次算是Industry level,但区别仅仅是onsite的时候多一个人面而已(上次4个,这次5个)。这次onsite在waterloo office,比较小,跟mountain view肯定没法比。本来是个Austin的HR打来的,结果一听要H1B,果断转给加拿大这边了,呵呵......中午尝了下waterloo的免费午餐,勉勉强强,不过运气好有免费哈根达斯吃,顺便看了半场世界杯(正好世界杯期间),还是很爽的。看的时候还跟面试的人讨论了下世界杯,随口预测了个决赛是德国对阿根廷,没想带后来还真是这俩决赛,不知道这个对于给offer有没有什么影响╮(╯▽╰)╭。
其他也没啥好说的了。主要还是面试做题,然后剩一部分时间扯project。把现在工作上做的东西扯得天花乱缀,正好compiler这东西详细知道的人也不多,唬人还是很有用的。面试题目难度也差不太多,主要还是算法,略微带点数据结构,把题目发出来,感兴趣的可以做着玩玩,顺便附上我当时的想法(解法):
电话面试:
其实电面一开始问了一个比较有意思,但又不怎么算面试题的问题,问最喜欢的语言是什么,然后最喜欢其哪个功能。我大清早迷迷糊糊的,以为问最常用哪个语言,听完一半张口就说C++,然后问最喜欢那个功能愣住了,不知道该咋继续,只好硬着头皮说喜欢pointer,然后开始扯蛋……唉,早知道说python我还可以说些靠谱的……
0.a 一个图,有n个顶点,让你加边,要求没有cycle,问最多能加多少条边
0.b 如果这是个有向图(Directed Graph),问最多可以加多少条边
* 其实这基本上是热身题了,前面一个,一个图没有cycle,就是tree嘛,n个顶点的tree就是n-1条边咯。至于第二问,我倒是证明了一下。首先可以把所有的顶点排序,每个顶点往其之后的顶点连一条单向边,这样就有n(n-1)/2条边而且无cycle。然后可以用抽屉原理证明n(n-1)/2+1条边的时候必然会有cycle,所以最后答案是n(n-1)/2
1. 给你一个字典,有以下一个method:
string getWord(int index){...}
Implement以下函数:
int getIndex(string word)
已知条件:
a. index按顺序排列,0,1,2....,中间没有空档
b. 所有word是按字母顺序排列的
c. 当index过大,getWord 返回NULL。所以可以同里,word不存在是getIndex返回NULL
* 这道题才是电面的正题。其实基本上等同于问,在一个不知道长度的,已经排序的array里找一个值。解法倒不算难,single sided binary search找一个boundary,然后在这个boundary中binary search。不过大清早做得电面,没睡醒,当时手打代码各种bug...
Onsite:
0.a 如何生成正方形中的随机点
0.b 如何用生成随机点的方式模拟π
0.c 写一个函数来生成π,要求用的次数越多,这个函数给的值越精确
* onsite第一个人,总的来说还是很简单的。a就不说了,会用随机函数就行。b的做法是在正方形里画个圆,然后在正方形内生成随机点,生成一定数量后,把园内的点数量乘4,再除以总生成的点数就行了。c我的做法是用b的方法,但是每次用完后记录下历史信息,这样下次用这个函数的适合可以沿用之前的数据,因为点越多越精确,所以这样可以保证返回的结果越来越接近正确的π
1. 输入一个string,输出这个string是fixed-point的所有permutation
解释:
1. fixed-point: 如果f(v) = v,那么v就是f的一个fixed-point
2. 每个permutation,就是置换,可以看作是一个函数,即输入一串字符,输出的是按照规则置换后的结果
* 这题目原叙述就第一行那样,没有解释,简直抽象到不行......这题目暴力解是exponential time,我想到的解法是暴力+subtree elimination。具体就不说了,比较复杂,worst case还是exponential,不过一般来讲可以跳过大多数的check,所以基本可以terminate... 不过面试之后想了想,这题说不定有更好的解法。比如说输入abcde,每位都不同那么这个的肯定只是一个permutation的fixed point。而如果有重复的字母,那才有可能是这两位交换的permutation的fixed-point. 所以,说不定可以找到一个办法直接看input生成。
2. Box sorting: 你有从1到n这n个数字,然后随机放在编号从1到n的盒子里,然后你还有一个编号为n+1的空盒子。你只有两个access的方法:
1. get(int p) - 返回编号为p的盒子里面有什么
2. move(int p, int q) - 把p盒子里的数移动到q盒子里
要求把每个数字放到同样编号的盒子里,并且要求用move的次数最少
* 这题目,排序简单,要求最少的move才是难点。我用的是一个偏贪心的算法:找一个与数字不匹配的盒子,把数字移到n+1(空盒子)里,然后这个盒子就空了,然后找到正确的数字移过来,以此类推,知道n+1再次为空,然后检查一遍还有没有剩余的编号不匹配的数字...这个算法结果最后是正确的,move次数似乎也是最少的,但要我证明最后没证出来...
3. 有一个N*N的矩阵,然后implement以下两个method:
1. setValue(int x, int y, int v) - 把坐标为x,y的值设为v
2. getSum(int x0, int x1, int y0, int y1) - 返回其中x0~x1, y0~y1 范围内所有值的和
要求:尽量的快!
* 这题目怎么看都在说4个字:动态规划。好多中间结果啊!赶快记录下来啊!不过这不是简单的动态规划,因为setValue会让一部分中间结果产生变化。所以具体的实现方法有很多,在不同情况下各有利弊....反正我跟面试官聊了小半个小时的“分情况讨论”...
4.a 如何验证一个string是不是unicode string
4.b 在一个m*n的棋盘上,按随机排列填入1~m*n,然后找到其中最长的连续递增的数列。连续必须是上下左右相连,例如下面最长的数列是1234:
8 5 9
2 3 4
1 6 7
* 其实这是最后一个面试,但题目却完全是基本功。第一题没啥好讲的,有很多写法,我差点直接画个Finite State Machine。第二个也不太难,规划一下O(n*m) (原来写的O(n)其实意思是想说linear time)就能解决。
O(n)