头条面试-后台研发实习

来源:互联网 发布:汽车电路软件下载 编辑:程序博客网 时间:2024/06/05 10:35

头条面试的一个特点就是等,面一个小时,等一个小时,从下午五点到中航广场,晚上将近10点才离开,一共经历三面。面试中主要是算法和项目,三个面试官不约而同对简历上仅有的一个实验室项目感兴趣(可能是因为这个项目偏研究,简历上其他项目都偏工程)。项目相关的东西因人而异,在此不做过多介绍。每次面试有两道算法题,写代码主要是看代码风格和逻辑严密性(比如边界条件,初始化,终止条件等),然后会让讲思路,不断优化,过程是讨论式的,如果暂时想不到还可以要求提示。

一面

两道题,第一道题是数组相关 ,原谅我饿着肚子面试不记得题目了。
第二道是二叉树((root)寻找两个节点(p,q)最近公共祖先。之前虽然见过这道题,但没认真记住,所以写代码实现的时候写了最容易想到的思路:

  1. 边界条件:root,p,q不为空,否则直接返回NULL;
  2. 判断p或者q是否等于root,若等于,则在root左右子树中查找另一节点,找到则返回root,否则返回NULL;
  3. 若p和q不等于root,分别在左右子树查找p和q,若p和q分别在左右子树,返回root,否则,递归同时包含p和q的子树。

不过看面试官的反应并不满意,又让考虑下思路,这次我简单描述了一个非递归算法:

先找树中最左节点,若该节点等于p或者q,则在父节点和父节点的右子树中查找另一个节点,若找到则返回当前节点的父节点。
当然这里有一种特殊情况,如果最左节点有右子树,则应先在该节点的右子树中查找是否满足条件。

但这个思路虽然较第一个思路优化了不少,应该也不是面试官想要的,最后也没有想到,一面就到此为止。从面试房间出来在等候区查了一下这个题,各种思路一大堆,没怎么认真看,有兴趣的多多调研,可以交流下。

二面

第一道是经典的求100万个数最大的k个数,然后将这个数量级提升到100亿中求最大k个数,大概说了下思路,建小顶堆,数量级大的时候先分片再找。
第二题是给定一个有序数组,然后给定数组中存在的一个数k,求数组中与k绝对值之差最小的c个数。稍加分析可以发现,满足条件的c个数在数组中一定是连续的,可以用反证法证明,如果不连续,则在缺失的部分可以找到一个数a,其中a与k的绝对值之差必定小于c个数中下标最小的数和下标最大的数中的一个。
有了以上结论,此问题即转化为寻找c个数中下标最小的数的位置m,从时间复杂度考虑,采用二分查找即可。记有序数组为nums,则二分查找的终止条件为:

|k-nums[m]|<=|nums[m+c]-k| && |k-nums[m-1]|>|nums[m+c]-k|

查找结束后,下标[m,m+c-1]中的c个数即为所求,当然此处还要考虑数字k的位置,如果k的下标在[m,m+c-1]之间,则应考虑加入nums[m-1]和nums[m+c]中离k最近的一个。

三面

第一个题被问的措手不及,因为是和概率相关,一不留神就想多了,写了一个自己都看不懂的公式,成功的被面试官证明是错的。问题描述如下:假设有一个n面的骰子,指定每个面朝上的概率为Pi(i=1,2,3,…,n),要求写一个类实现初始化以及投掷骰子的函数(返回值为投掷一次朝上的面的数字),额外要求是注意代码风格。
这个问题首先是要生成一个随机数,我考虑的是生成1到n之间的随机数,然后再随机,然后成功的晕了。但其实只要生成[0,1]区间的随机数,如果随机数落在[sum(P1:Pi-1),sum(P1:Pi)]区间则返回i即可,落在[0,P1]区间返回1。
第二个题是求数列中第k大的数,因为二面的时候遇到的是求k个最大的数,所以首先考虑的也是建立小顶堆,然后遍历,但时间复杂度为O(n*logk),空间复杂度为O(k),并不是最优的解;再思考了一下,又想到用一个额外的数组记录比当前数字大的数字个数,然后再一趟遍历查找这个额外数组中值刚好为k-1的位置对应的数字即为所得,时间复杂度和空间复杂度均为O(n),面试官让再想想。对比本题和求k个最大数的区别,空间复杂度应该为O(1)才最优,时间复杂度再优化下去应该是O(logn),所以只有二分查找能满足,由此想到快排中分治的思想,一趟快排之后前后两部分分别是比当前数字小和大的数字,所以可以判断当前数字是第几大的数,如果不是第k大的,继续在左边或者右边查找即可。

面完头条找实习的过程就到此为止啦,终于赶上校招末班车,坐等七月。