百度面试题(不断更新)


1 从输入url到显示网页,后台发生了什么?
当在浏览器中输入一个 url 后回车,后台发生了什么?比如输入 http://hi.baidu.com/mianshiti 后,你看到了IT面试题的博客首页,那么这一切是如何发生的呢?
简单来说有以下步骤:
(1). 查找域名对应的IP地址。这一步会依次查找浏览器缓存,系统缓存,路由器缓存,ISP DNS缓存,根域名服务器。
(2). IP对应的服务器发送请求。
(3). 服务器响应请求,发回网页内容。
(4). 浏览器解析网页内容。
当然,由于网页可能有重定向,或者嵌入了图片,AJAX,其它子网页等等,这4个步骤可能反复进行多次才能将最终页面展示给用户。
2 三个警察和三个囚徒共同旅行。一条河挡住了去路,河边有一条船,但是每次只能载2人。存在如下的危险:无论在河的哪边,当囚徒人数多于警察的人数时,将有警察被囚徒杀死。问题:请问如何确定渡河方案,才能保证6人安全无损的过河。
警察囚徒过去,警察回来
囚徒囚徒过去,囚徒回来
警察警察过去,警察囚徒回来
警察警察过去,囚徒回来
囚徒囚徒过去,囚徒回来
囚徒囚徒过去

3 设计DNS服务器中cache的数据结构

要求设计一个DNSCache结构,要求能够满足每秒5000以上的查询,满足IP数据的快速插入,查询的速度要快。(题目还给出了一系列的数据,比如:站点数总共为5000万,IP地址有1000万,等等)

DNS服务器实现域名到IP地址的转换。

每个域名的平均长度为25个字节(估计值),每个IP4个字节,所以Cache的每个条目需要大概30个字节。

总共50M个条目,所以需要1.5G个字节的空间。可以放置在内存中。(考虑到每秒5000次操作的限制,也只能放在内存中。)

 

可以考虑的数据结构包括hash_map,字典树,红黑树等等。

我觉得比较好的解决方法是,将每一个URL字符串转化为MD5值,作为key,建立最大或最小堆,这样插入和查找的效率都是O(log(n))

MD5128bit的大整数也就是16byte,比直接存放URL要节省的多。

 

4 将多个集合合并成没有交集的集合

给定一个字符串的集合,格式如:{aaa bbb ccc} {bbb ddd}{eee fff}{ggg}{ddd hhh}要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,例如上例应输出{aaa bbb ccc ddd hhh}{eee fff} {ggg}

1)请描述你解决这个问题的思路;

2)请给出主要的处理流程,算法,以及算法的复杂度

3)请描述可能的改进。

 

集合使用hash_set来表示,这样合并时间复杂度比较低。

 

1. 给每个集合编号为0123...

2. 创建一个hash_mapkey为字符串,value为一个链表,链表节点为字符串所在集合的编号。遍历所有的集合,将字符串和对应的集合编号插入到hash_map中去。

3. 创建一个长度等于集合个数的int数组,表示集合间的合并关系。例如,下标为5的元素值为3,表示将下标为5的集合合并到下标为3的集合中去。

开始时将所有值都初始化为-1,表示集合间没有互相合并。

在集合合并的过程中,我们将所有的字符串都合并到编号较小的集合中去。

遍历第二步中生成的hash_map,对于每个value中的链表,首先找到最小的集合编号(有些集合已经被合并过,需要顺着合并关系数组找到合并后的集合编号),然后将链表中所有编号的集合都合并到编号最小的集合中(通过更改合并关系数组)。

4.现在合并关系数组中值为-1的集合即为最终的集合,它的元素来源于所有直接或间接指向它的集合。

题目中的例子:

0: {aaa bbb ccc}

1: {bbb ddd}

2: {eee fff}

3: {ggg}

4: {ddd hhh}

生成的hash_map,和处理完每个值后的合并关系数组分别为

aaa: 0[-1, -1, -1, -1, -1]

bbb: 0, 1[-1, 0, -1, -1, -1]

ccc: 0[-1, 0, -1, -1, -1]

ddd: 1, 4[-1, 0, -1, -1, 0]

eee: 2[-1, 0, -1, -1, 0]

fff: 2[-1, 0, -1, -1, 0]

ggg: 3[-1, 0, -1, -1, 0]

hhh: 4[-1, 0, -1, -1, 0]

所以合并完后有三个集合,第014个集合合并到了一起,

23个集合没有进行合并。

 

算法的复杂度为O(n),其中n为所有集合中的元素个数。

哈希表加并差集,先用哈希把字符串转成整数,转换的时候就用并差集来操作求集合的并,建立哈希O(n) 哈希查询O(1) 并差集复杂度不好估计,大概为a*O(1)

 

5 求数组中出现次数超过一半的数(《编程之美》寻找发帖“水王”)

一个数组中有很多数,现在我们要找出这个数组中那个超过出现次数一半的数字,怎么找呢?大凡当我们碰到某一个杂乱无序的东西时,我们人的内心本质期望是希望把它梳理成有序的。所以,我们得分两种情况来讨论,无序和有序

  1. 思路一:如果无序,那么我们是不是可以先把数组中所有这些数字先进行排序,至于选取什么排序方法则不在话下,最常用的快速排序ON*logN)即可。排完序呢,直接遍历。在遍历整个数组的同时统计每个数字的出现次数,然后把那个出现次数超过一半的数字直接输出,题目便解答完成了。总的时间复杂度为ON*logN+N)。
  2. 思路二:但各位再想想,如果是有序的数组呢或者经过上述由无序的数组变成有序后的数组呢?是否在排完序ON*logN)后,真的还需要再遍历一次整个数组么?我们知道,既然是数组的话,那么我们可以根据数组索引支持直接定向到某一个数。我们发现,一个数字在数组中的出现次数超过了一半,那么在数组索引的N/2处(从零开始编号),就一定是这个数字。自此,我们只需要对整个数组排完序之后,然后直接输出数组中的第N/2处的数字即可,这个数字即是整个数组中出现次数超过一半的数字,总的时间复杂度由于少了最后一次整个数组的遍历,缩小到ON*logN)。
  3.  然不论是上述思路一的ON*logN+N),还是思路二的ON*logN),时间复杂度并无本质性的改变。
  4. 思路3:我们需要找到一种更为有效的思路或方法。既要要缩小总的时间复杂度,那么就用查找时间复杂度为O1),事先预处理时间复杂度为ON)hash表。哈希表的键值(Key)为数组中的数字,值(Value)为该数字对应的次数。然后直接遍历整个hash表,找出每一个数字在对应的位置处出现的次数,输出那个出现次数超过一半的数字即可。
  5. 思路4:Hash表需要ON)的开销空间,且要设计hash函数,还有没有更好的办法呢?我们可以试着这么考虑,如果每次删除两个不同的数(不管是不是我们要查找的那个出现次数超过一半的数字),那么,在剩下的数中,我们要查找的数(出现次数超过一半)出现的次数仍然超过总数的一半。通过不断重复这个过程,不断排除掉其它的数,最终找到那个出现次数超过一半的数字。这个方法,免去了上述思路一、二的排序,也避免了思路三空间ON)的开销,总得说来,时间复杂度只有ON),空间复杂度为O1),不失为最佳方法。

    或许,你还没有明白上述思路4的意思,举个简单的例子吧,如数组a[5]={0,1,2,1,1};

    很显然,若我们要找出数组a中出现次数超过一半的数字,这个数字便是1,若根据上述思路4所述的方法来查找,我们应该怎么做呢?通过一次性遍历整个数组,然后每次删除相同的两个数字,过程如下简单表示:

0 1 2 1 1 =>2 1 1=>1,最终,1即为所找。

    Ok,思路清楚了,那么接下来,咱们就来写代码实现上述思路4所述的方法:

//改自编程之美 2010
Type Find(Type* a, int N)  //a代表数组,N代表数组长度
{
Type candidate;
int nTimes, i;
for(i = nTimes = 0; i < N; i++)
{
if(nTimes == 0)
{
candidate = a[i], nTimes = 1;
}
else
{
if(candidate == a[i])
nTimes++;
else
nTimes--;
}
}
return candidate; 
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值