腾讯面试题

求一个论坛的在线人数,假设有一个论坛,其注册ID有两亿个,每个ID从登陆到退出会向一个日志文件中记下登陆时间和退出时间,要求写一个算法统计一天中论坛的用户在线分布,取样粒度为秒。
回答:
  一天总共有3600*24=86400秒。
  定义一个长度为86400的整数数组intdelta[86400],每个整数对应这一秒的人数变化值,可能为正也可能为负。开始时将数组元素都初始化为0。
  然后依次读入每个用户的登录时间和退出时间,将与登录时间对应的整数值加1,将与退出时间对应的整数值减1。
  这样处理一遍后数组中存储了每秒中的人数变化情况。
  定义另外一个长度为86400的整数数组intonline_num[86400],每个整数对应这一秒的论坛在线人数。
  假设一天开始时论坛在线人数为0,则第1秒的人数online_num[0]=delta[0]。第n+1秒的人数online_num[n]=online_num[n-1]+delta[n]。
  这样我们就获得了一天中任意时间的在线人数。

9、三个警察和三个囚徒的过河问题

  三个警察和三个囚徒共同旅行。一条河挡住了去路,河边有一条船,但是每次只能载2人。存在如下的危险:无论在河的哪边,当囚徒人数多于警察的人数时,将有警察被囚徒杀死。问题:请问如何确定渡河方案,才能保证6人安全无损的过河。
答案:第一次:两囚徒同过,回一囚徒
第二次:两囚徒同过,回一囚徒
第三次:两警察同过,回一囚徒一警察(此时对岸还剩下一囚徒一警察,是安全状态)
第四次:两警察同过,回一囚徒(此时对岸有3个警察,是安全状态)
第五次:两囚徒同过,回一囚徒
第六次:两囚徒同过;over

10、从300万字符串中找到最热门的10条
搜索的输入信息是一个字符串,统计300万输入信息中的最热门的前10条,我们每次输入的一个字符串为不超过255byte,内存使用只有1G。请描述思想,写出算法(c语言),空间和时间复杂度。
答案:
  300万个字符串最多(假设没有重复,都是最大长度)占用内存3M*1K/4=0.75G。所以可以将所有字符串都存放在内存中进行处理。
  可以使用key为字符串(事实上是字符串的hash值),值为字符串出现次数的hash来统计每个每个字符串出现的次数。并用一个长度为10的数组/链表来存储目前出现次数最多的10个字符串。
  这样空间和时间的复杂度都是O(n)。
11、如何找出字典中的兄弟单词。给定一个单词a,如果通过交换单词中字母的顺序可以得到另外的单词b,那么定义b是a的兄弟单词。现在给定一个字典,用户输入一个单词,如何根据字典找出这个单词有多少个兄弟单词?
答案:
  使用hash_map和链表。
  首先定义一个key,使得兄弟单词有相同的key,不是兄弟的单词有不同的key。例如,将单词按字母从小到大重新排序后作为其key,比如bad的key为abd,good的key为dgoo。
  使用链表将所有兄弟单词串在一起,hash_map的key为单词的key,value为链表的起始地址。
  开始时,先遍历字典,将每个单词都按照key加入到对应的链表当中。当需要找兄弟单词时,只需求取这个单词的key,然后到hash_map中找到对应的链表即可。
  这样创建hash_map时时间复杂度为O(n),查找兄弟单词时时间复杂度是O(1)。
12、找出数组中出现次数超过一半的数,现在有一个数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数。
答案1:
  创建一个hash_map,key为数组中的数,value为此数出现的次数。遍历一遍数组,用hash_map统计每个数出现的次数,并用两个值存储目前出现次数最多的数和对应出现的次数。
  这样可以做到O(n)的时间复杂度和O(n)的空间复杂度,满足题目的要求。
  但是没有利用“一个数出现的次数超过了一半”这个特点。也许算法还有提高的空间。
答案2:
  使用两个变量A和B,其中A存储某个数组中的数,B用来计数。开始时将B初始化为0。
  遍历数组,如果B=0,则令A等于当前数,令B等于1;如果当前数与A相同,则B=B+1;如果当前数与A不同,则令B=B-1。遍历结束时,A中的数就是要找的数。
  这个算法的时间复杂度是O(n),空间复杂度为O(1)。

13、找出被修改过的数字
      n个空间(其中n<1M),存放a到a+n-1的数,位置随机且数字不重复,a为正且未知。现在第一个空间的数被误设置为-1。已经知道被修改的数不是最小的。请找出被修改的数字是多少。
  例如:n=6,a=2,原始的串为5,3,7,6,2,4。现在被别人修改为-1,3,7,6,2,4。现在希望找到5。
回答:
  由于修改的数不是最小的,所以遍历第二个空间到最后一个空间可以得到a的值。
  a到a+n-1这n个数的和是total=na+(n-1)n/2。
  将第二个至最后一个空间的数累加获得sub_total。
  那么被修改的数就是total-sub_total。

(有溢出危险)

 

第2种方法:

 

做一个抑或操作,一个数x,x^x=0,x^0=x,所以修改后的第二个空间到最后一个空间所有数抑或一遍,然后再抑或a到a+n-1,相当于(3^3)^(7^7)...(4^4)^5=5^0=5,结果就是被修改的数字。

14、设计DNS服务器中cache的数据结构。
  要求设计一个DNS的Cache结构,要求能够满足每秒5000以上的查询,满足IP数据的快速插入,查询的速度要快。(题目还给出了一系列的数据,比如:站点数总共为5000万,IP地址有1000万,等等)
回答:
  DNS服务器实现域名到IP地址的转换。
  每个域名的平均长度为25个字节(估计值),每个IP为4个字节,所以Cache的每个条目需要大概30个字节。
  总共50M个条目,所以需要1.5G个字节的空间。可以放置在内存中。(考虑到每秒5000次操作的限制,也只能放在内存中。)
  可以考虑的数据结构包括hash_map,字典树,红黑树等等。
15、找出给定字符串对应的序号。
  序列Seq=[a,b,…z,aa,ab…az,ba,bb,…bz,…,za,zb,…zz,aaa,…]类似与excel的排列,任意给出一个字符串s=[a-z]+(由a-z字符组成的任意长度字符串),请问s是序列Seq的第几个。
回答:
  注意到每满26个就会向前进一位,类似一个26进制的问题。
  比如ab,则位置为26*1+2;
  比如za,则位置为26*26+1;
  比如abc,则位置为26*26*1+26*2+3;
16、找出第k大的数字所在的位置。写一段程序,找出数组中第k大小的数,输出数所在的位置。例如{2,4,3,4,7}中,第一大的数是7,位置在4。第二大、第三大的数都是4,位置在1、3随便输出哪一个均可。
答案:
   先找到第k大的数字,然后再遍历一遍数组找到它的位置。所以题目的难点在于如何最高效的找到第k大的数。
 我们可以通过快速排序,堆排序等高效的排序算法对数组进行排序,然后找到第k大的数字。这样总体复杂度为O(NlogN)。
 我们还可以通过二分的思想,找到第k大的数字,而不必对整个数组排序。从数组中随机选一个数t,通过让这个数和其它数比较,我们可以将整个数组分成了两部分并且满足,{x,xx,...,t}<{y,yy,...}。
 在将数组分成两个数组的过程中,我们还可以记录每个子数组的大小。这样我们就可以确定第k大的数字在哪个子数组中。
 然后我们继续对包含第k大数字的子数组进行同样的划分,直到找到第k大的数字为止。
 平均来说,由于每次划分都会使子数组缩小到原来1/2,所以整个过程的复杂度为O(N)。

17、给40亿个不重复的unsigned int的整数,没排过序的,然后再给几个数,如何快速判断这几个数是否在那40亿个数当中?
答案:
  unsigned int的取值范围是0到2^32-1。我们可以申请连续的2^32/8=512M的内存,用每一个bit对应一个unsigned int数字。首先将512M内存都初始化为0,然后每处理一个数字就将其对应的bit设置为1。当需要查询时,直接找到对应bit,看其值是0还是1即可。

18、在一个文件中有10G个整数,乱序排列,要求找出中位数。内存限制为2G。

解法:首先假设是32位无符号整数。
1. 读一遍10G个整数,把整数映射到256M个区段中,用一个64位无符号整数给每个相应区段记数。
说明:整数范围是0 - 2^32 - 1,一共有4G种取值,映射到256M个区段,则每个区段有16(4G/256M = 16)种值,每16个值算一段, 0~15是第1段,16~31是第2段,……2^32-16 ~2^32-1是第256M段。一个64位无符号整数最大值是0~8G-1,这里先不考虑溢出的情况。总共占用内存256M×8B=2GB。

 

2. 从前到后对每一段的计数累加,当累加的和超过5G时停止,找出这个区段(即累加停止时达到的区段,也是中位数所在的区段)的数值范围,设为[a,a+15],同时记录累加到前一个区段的总数,设为m。然后,释放除这个区段占用的内存。

 

3. 再读一遍10G个整数,把在[a,a+15]内的每个值计数,即有16个计数。

 

4. 对新的计数依次累加,每次的和设为n,当m+n的值超过5G时停止,此时的这个计数所对应的数就是中位数。

 

总结:
1.以上方法只要读两遍整数,对每个整数也只是常数时间的操作,总体来说是线性时间。

21、平面内有11个点,由它们连成48条不同的直,由这些点可连成多少个三角形?
解析:
首先你要分析,平面中有11个点,如果这些点中任意三点都没有共线的,那么一共应该有C(11,2)=55,  可是,题目中说可以连接成48条直线,那么这11个点中必定有多点共线的情况。  55-48=7,从7来分析:
假设有一组三个点共线,那么可以组成的直线在55的基础上应该减去C(3,2)-1=2     2*3=6≠7,因此,可以断定不仅有三点共线的,也可能有四个点共线的可能。
假设有一组四个点共线,那么可以组成的直线在55的基础上应该减去C(4,2)-1=5
(备注,五个点共线的可能不存在,因为,C(5,2)-1=9>7,故不可能有五条直线共线。)

因此,三点共线少2条,4点共线少5条,只有一个4点共线,一个3点共线才能满足条件,其余情况不能满足少了7条直线。
那么,这11个点能组成的三角形的个数为,C(11,3)-C(3,3)-C(4,3)=165-1-4=160  (备注,三个点共线不能组成三角形)

 

 

posted @ 2013-08-19 14:49  sandyhit  阅读(225)  评论(0编辑  收藏  举报