一共参加了1次笔试,3次面试。总的感觉是,微软暑期实习的笔试难度不算很大,面试难度随面试官而异,毕竟是微软,卧虎藏龙的地方,面试官想虐人还是非常容易的。
1.笔试
笔试挺简单,虽然2013年的题和2012年的一点也不一样,但是大体思路是一样的。前面一部分简单题是考C,C++基础知识的,后面一部分是考算法、概率、信息论等稍微高一些的理论的。全是选择题,答错、不答扣分,少答给一部分分数,全部答对才得满分。考前我看了点C++ Primer,算法导论一直在研究,所以后面答的还不错,基本没错,前面的就比较惨了,C++用的太少,错了好多道。不过微软笔试设的门槛不算高,按照网上的答案我卷面大概有70分,不过40分左右应该就可以进面试了。
2.一面,二面
微软的一面和二面是在一起的,两位面试官,每位面一个小时。规则是:如果两位面试官都对面试者满意/不满意,面试者直接拿到offer/被淘汰,如果两位面试官意见不统一,会在几天之后安排加面,也就是三面,最终的录取结果会在一段时间后通知(今年是五一之后,被淘汰的好像不会收到通知)。我被安排在了4月21日下午面试,面试时间是根据什么安排的众说纷纭,这个也不好揣测,可能微软有自己比较复杂的算法吧。在这之前,Jeans和我gf分别在前一天和上午进行的面试,他们面试的情况比较相似,都是以问算法和数据结构题为主,题的难度是由浅入深,开始的简单题例如:斐波那契数列、判断平衡二叉树、链表反转、字符串转整数等都需要编程,而后面的一些复杂题或者开放性问题只要求说出算法,不太需要实际的编程。然后我抱着这种心态去参加了下午的面试,没想到完完全全被虐了。每个面试官只问了一道题,也就是说,一上来就是比较难的题,完全没有简单题热身。
第一个面试官首先看着我的简历问了一些问题。然后看到我在android手机上写过一个程序,问我这个程序是否考虑过扩展性和移植性。我大致讲了一下我在设计程序的时候是怎么考虑这些问题的,接着掏出手机给他展示了一下,他说做的挺酷的,然后简历部分就结束了,询问简历这部分大概只有15分钟。接下来就是做题了,他出的题目是“输出排序二叉树任意节点的后继”,其实这道题不算很难,就算不能完全写出程序,大致框架写出来应该是没问题的,只是我当时生病&紧张,一上来就问这种难度的,和预期的差距太大,心里有点慌。自己写了大概20分钟,写得不是很对,然后他稍微提示了一下,我又根据新的思路写了20分钟,不过一直到最后,也没有把完整的程序写出来。后来想了想,思路有一定难度,程序编起来也比较费劲,思路如下:
节点的后继指的是二叉树中序遍历时,该节点之后遍历到的节点。分两种情况:
1.如果该节点有右子树,则后继是它的右子树中最左边的节点。
2.如果该节点没有右子树并且该节点是它的父节点的左孩子,则后继是它的父节点。
3.如果该节点没有右子树并且该节点是它的父节点的右孩子,则后继是满足“距离它最近的、左孩子也是它的祖先的”祖先节点。如果找不到这样一个节点,那么该节点没有后继,即该节点是排序二叉树中序遍历的最后一个输出。
回学校之后我在网上找了一下,只找到一个大概80行的代码实现,不过这个实现是给排序二叉树加上了parent指针。按照正常的二叉树来做的话,还需要维护一个栈来存储祖先节点,代码量应该有100行左右。
第一面就这么悲惨的结束了,感觉自己完全被虐了,其实还是自己的准备不太充分,而且状态不够好。
接下来是二面,也是一位难对付的面试官。上来看了一下我的简历,基本没问什么,直接就开始做题。题目是:设计一棵多叉树,即一个节点可以有多个孩子节点,不允许用二叉树方法表示。我是从来没有见过&做过类似的题,只能硬想。我提出用孩子,兄弟表示法,但是他说这就是个二叉树,所以不可以。然后我又向他确认了每个节点的孩子数量是否有最大限制,他回答可以有。又想了一会,我把自己的想法整理了一下,跟他说了。简答来说,就是每个节点有几个域:一维父指针、二维孩子指针(存储所有孩子节点指针)、key值。他不置可否,让我继续写一个删除某一节点的操作,我写完之后他又要求输入是根节点,我就又加了一个遍历树的功能。总算是全部都写完了,他说让我分析一下我的代码有什么没考虑到的地方,我指出了几点:需要删除节点、根节点为NULL,需要删除节点不在树里面,需要删除节点的孩子数量+需要删除节点的父节点的孩子数量大于最大数量上限等等。他听了之后,啥也没说,这道题就这么结束了。剩下的二十分钟,他就随意问了我一些简历里面的东西,让我讲解一下adaboost分类器,分析刚才题目里面操作的时间复杂度,甚至还问我怎么看待自己的编程能力。……然后二面就在非常冷气氛中结束了。总结下来就是,他问我,我回答,他无反馈,我问他,他不高兴。
那天走出微软大厦的时候真心感觉和微软无缘了,呵呵。
3.三面
一面二面之后我以为没戏了,没想到微软给我发了三面通知。三面一共一个小时,面试我的是一位女面试官。跟之前一样,首先问了大概5分钟的简历。然后就开始做题,题目如下:
1.两个均大于3的连续奇数,并且都是质数,证明两个连续奇数中间的那个数可以被6整除
解:这是一道数学题,首先,两个连续奇数中间的书肯定是偶数,必能被2整除,因此问题简化成证明中间的这个偶数可以被3整除。因为两个奇数都是质数,因此两数都不能被3整除。假设第一个奇数除以3之后余1,那么因为第二个奇数比第一个奇数大2,因此第二个奇数除以3余1+2=3,因此第二个奇数可以被3整除,这与条件矛盾。所以第一个奇数除以3余2,第二个奇数除以3余1,那么两个奇数中间的那个偶数一定能被3整除,一个数,即可以被3整数又可以被2整除,一定能被6整除。
2.有大量的无序浮点数,取值范围从0到1000,怎样找到这些数的中位数
解:方法类似于桶排序,假设数字的总数量为N,那么根据N的大小,分配每个桶的容量,保证桶的数量不至于大到无法装入内存,并且桶的容量尽量的小。然后将数据依次放入桶中,接下来从最小的桶开始,逐个累计每个桶中数的数量,如果加到第i个桶时,数量首次超过了N/2,那么中位数一定在这个桶中,假设这个桶中浮点数的数量为k,累计的浮点数总数为m(不包括第i个桶),那么只要在这k个数中寻找第(N/2-m)大的数即可。用快排的partition方法就能在o(log k)的时间复杂度内找到。
3.双向链表的逆转
这个比较简单,就不说了,只要代码写的没问题即可。