http://eager2007.blog.hexun.com/26216090_d.html
本来今天想写的是“面试记”,八一八HR姐姐和面试官叔叔。但聊到面试难免要聊面试题,而算法题自是其重中之重。为了日后能专心地八面试官,今天就先说说这个算法。。。
本篇涉及专业知识,外行止步,发生危险概不负责。
算法与数据结构,属于IT技能中较“高雅”的一类,所谓阳春白雪、曲高和寡,往往只有大公司才对此有兴趣。而急功近利的小公司面试官只会问“会不会用Struts”之类……
其 中,数据结构比较基础些。一般开发类职位都会考考Linked List或者Hash table之类的,相信上过这门课的人都能写出来。要求更高的面试官会真正地考算法,(而不仅仅是数据结构)。算法有两种考法,一是考课本知识,主要集中 在排序、查找和二叉树相关三类算法。考查的是基础知识掌握,以及编程基本功。
另一类就是考书上没有的算法,这往往出现在对创造性较高的岗位中。想要令面试官满意的话,完全寄希望于现场发挥是很难的,最好平时有算法方面的积累。建议大家平时多逛逛百合的Algorithm版什么的……另外百度历年的笔试题也是增加积累的好素材。
最后不得不提一个出场率最高的算法,我曾经在四场面试中用上它:
先排序再取数的做法需要O(n*Logn)的复杂度,事实上此问题O(n)可解。具体做法是:按照类似快速排序算 法中的“分类”步骤,任选一个参考数,把整个数组分成左右两部分。左边部分小于参考数,右边部分大于参考数。然后根据左右部分各自包含元素的个数,计算出 要求的元素在哪个数组中。(要求的元素或者是左数组中的第k小数,或者是右数组中第[k-l]小的数。l为左数组的长度)然后递归之。
贴个伪代码:
没看懂的话也没关系,百度一下“第k小数”或者“random select问题”会有更详细的解释。
如何向面试官描述这个算法:
如果手中有纸笔,画图可以描述地更清楚。如果是电话面抓住关键词“快排”“分类”“递归”即可。
进一步,面试官会问这个算法的复杂度。此算法额外空间复杂度为O(logn),可以进一步优化为O(1)——将递归改写为非递归即可。时间复杂度为O(n)——虽然乍看上似乎是n*Logn。平均每个数组元素被访问两次。
时间复杂度的证明是另一个关键,如果证不出来赶快百度一下啦。
下面解释为什么这个算法在面试中的应用:
首先,此问题可以推广:求数组中最小的k个数(而不是第k小的数)。答案很简单:求出第k小数之后,其左边的(k-1)个数都比它小。所以……
其次,它可以退化求中位数问题:如何在O(n)时间内求数组的中位数。
我曾在某次面试中被提了这个问题,随后面试官又推广了此问题。他问道:
(注,当数组长度为偶数时,中位数有两种不同的定义。此处定义第[n/2]个数为中位数,而不是中间两数之平均。)
也许不可思议,此问题仍然有O(n)的解法:
可以证明:如果将数组排序,那么问题等价于求数组最中间的一段k个数。当然“最中间一段”这样的说法有些含糊,但大致上就是求下标为[n/2-k/2, n/2+k/2]这个区间上的一段数,但是在区间两端要根据n和k的奇偶性作+1或-1的调整。因此,原问题转化为:
剩下的问题就很简单了:先求原数组中最小的b个数,然后在此结果中求最大的(b-a+1)个数。
最后一个推广,此算法还可以用在著名的“主元素”问题上。主元素的定义是:
主元素问题就是:
使用Random select算法,可以在O(n)时间内解决此问题:1 求中位数。2 检验中位数是否为主元素。
不过这样需要平均扫描每个元素3次。事实上此问题还有更巧妙的解法,可以只扫描每个元素2次。欲知解法如何,去Google上百度一下……