CCI 复习笔记 11

飞去西雅图面微软之前我基本上看完了第8,10,11,12,13。当然由于在飞机上,我没有认真写笔记,现在重新写起


先写11章,因为11章比较基础,其他章节最近也会补上。去微软面试让我的感觉就是,要么就是我目前做基础题的水平已经差不多够了,要么就是我运气比较好,虽然不是特别顺利,但是没有卡壳做不出来的时候。我觉得我目前的水平,大约也就在这里了。。。


这次的经历让我坚定了之前的一个体会,If you want to be one of them, you have to be one of them first.


11.1 两个已经排序的array,A的后面有足够的地方保存B,如何merge A和B


这题我之前一直想的是把B直接拷贝到A里面去,然后做一个复杂的交换算法。但是书上的方法是,直接从尾巴开始做merge,然后就没有任何问题了。。。。


11.2 做一个排序,保证同字母字串(anagrams)被排在一起


这题难度略小,就是重新定义一种cmp方程而已。书上的方法基本上就是把字符串排序,之后使用排序后的字符串作为key,保存在一起再输出,因为key之间的顺序关系其实并没没有要求。


在python里面,直接做字符串的sorted(),会转变成list,所以还要再join一下。


11.3 一个已经rotate之后的array,搜索某一个数字


rotate是个神奇的操作,就是locally还是保持了相对的性质,所以就是还是检测中间的就可以了。其实没啥难度,如果比较left以及mid,


对于一个例子456123。。

如果mid>left, 那么断层在右边

如果mid


如果断层在右边,如果A>mid,那么A在右边;如果left

如果断层在左边,如果Aleft>mid,A在左边


似乎并没有更简洁的rule,就这样把。目前这类题真的在面试里面考到还是很难做对的。。。


11.4 巨大的文件,如何sort


分开sort,然后再merge。这题没啥,但是更深一点思考,如何用MR来做这个题呢?docId是key,value是string以及local rank,以及diskId,到了reduce的步骤,在这种情况下,必须是什么卵用都没有。只能是Map就出一个假key,然后一个docid和string的pair,reduce做正常merge,但是如果是这样,和正常算法并没有什么区别。。。这个貌似不大合适。。


11.5 一个sort的string array,里面充满了很多空字符串,咋办?


这题的主要难度在于,有三种情况要考虑,如果mid是空的以后,用while loop两路检测,直到碰到非空为止。


11.6 一个matrix,行和列都被排序了,如何检测一个element


这道题应该脑洞比较大,我最初是把想成一个数值问题,但是后来发现这个题目的最奇特的地方在于,你可以把整个看做一个3D里面的一个平面,但是对于某一个数来说,它可以出现的地方(想象成Z值),其实是一个平面和这个斜面的交线,是一条线来的。当然了,由于离散问题,最后的值其实很少。

1 2.2 2.5

2 3.5 4

3 3.7 5

所以我觉得第一种做法可以是这样,从M[h-1][w-1]开始,沿某一个方向检测(比如说向上),找到比它大得最后一个数字(且下一个数字不是它),然后曲折寻找。要找4.2,是5-4-3.5-3.7,大了就往右边走,小了就往下走。

然后这里有一个问题,为什么当前数字大了之后是向左走而不是向上走。由于最初的检测时候保证了数字A一定大于当前行的所有数字,所以必须不可能在上面。


书上的第二个做法就是binary search的延伸。但是需要仔细分析。running time还是可以的, (log(N))^2。T(N) = 2*T(N/2) + log(N), N是边长, 但是算法复杂多了。而且有一个重点是,对于对角线的搜索应该用binary search


上一个查找算法貌似是线性。。。最多查找M+N?


11.7 马戏团叠人,必须x,y都小才能叠上去,问做多能叠多少个。


这题可以延续到无数维度。running time似乎可以保证在O(N^2),用书上cache的做法。如果用我的做法(这题在之前的post出现过),貌似大于3维就很麻烦


基本上的key point就是,考虑以某个人为bottom为一个sub problem,然后cache所有计算过的情况。

这个我会贴个代码上来。


11.8 读一个Stream,然后要求对于每一个数,可以output一个rank


首先,从data science的角度来讲,我的做法应该是用kernel estimation做一个PDF, 然后新数据进来之后estimate rank。 当然了我是在扯淡


正确的做法是做一个binary tree, 然后根据binary tree report。首先第一个问题是,你是不是需要事先implement rank呢?通常在建tree的时候keep track会更容易一点,但是貌似并不能完全解决问题,主要就是在于插入一个小数之后,所有都要改变。但是其实keep track tree size是容易的。


在记录的时候,很明显如果一个数据是左node还是右node是不一样的,但是问题在于,trace back to parent似乎并不是一个好主意。书上给出了一个解决的做法,一个node在从root的path上,每一次找到下一个node的时候都做一次判定,如果是left child,那么rank(x)和之前并没有影响,最终就是left_node_size(),如果在过程中有过时right children,说明它要大于这个值,那么这个rank在最后就要加上rank(current)+1, 而rank(current)到底怎么计算呢?为什么书上用的是leftchildren呢?

1           

   2

      3

    

        4 

   2

      3


首先,用rank(current)是不对的。。。。因为对于每次出现rightchildren,只有两种情况,要么parent是rightchildren,要么parent是leftchildren,如果parent是rightchild(第一种),那么,1的left_size就是最初的rank,2给出的就是除了小于1的以外,还剩下的部分。而如果用rank,显然多加了。


第二种情况就没啥可说的了,2是leftchild,所以2的rank自然就是,所有以rightchild传下来的祖先的left size加上自己的left size


这里可以看到,“所有以rightchild传下来的祖先“,必须就是他的上一个left祖先的rank,但是似乎cache rank并不是一个好主意,因为rank会经常大规模变化。从这个角度来说,这道题基本上做的事情,就是很本质的,找到所有比X小得数字,iteratively地加起来。



 





你可能感兴趣的:(CCI 复习笔记 11)