百度技术类笔试题经验

一面1. 718545485

网络编程经验:

   如何判断一个http请求,一个客户端请求已经结束;

首部的结束是以连续两个新行标记(\r\n)来表示的,
有了首部以后,剩下的数据可以根据首部中的 Content-Length 字段来计算其长度。

如何处理服务器多线程

   获得一个http请求后,是如何处理的?返回什么?有没有试过返回图片?

   服务器给客户端请求时,是用什么函数写?服务器如何获取客户端请求,用什么函数

   (需要函数级别的连接有一个认识)

 

2. cv操作是什么函数 cv_init,cv_wait, cv_signal

11. 在Solaris中,POSIX互斥锁主要用于线程间同步。说明POSIX互斥锁用于进程间同步时的主要步骤。(提示:使用系统调用mmap and ftruncate, 注意cleanup)。
◆ 互斥锁

互斥锁(mutex)使得某一确定时刻只有一个线程可以访问保护中的数据。

◆ 读/写锁

采用读写锁,允许多个线程同时读访问共享数据区,但是只能有一个线程写访问
共享数据区。

绝大多数设备驱动程序不使用读写锁。这种锁比互斥锁慢,仅当经常出现多个线
程需要同时读访问共享数据而同时较少有写访问时,才采用读写锁,互斥锁此时可能
导致写访问延迟。参看rwlock(9F)了解更多信息。

◆ 信号灯

信号灯也是设备驱动程序编写中一种可选的线程同步机制,参看semaphore(9F)
了解更多细节。

◆ 线程同步

除了需要保护共享数据区外,驱动程序经常需要保持多线程同步执行。

◆ 条件变量

条件变量是线程同步的标准形式,与互斥锁配合使用。互斥锁用于确保检查条件
变量时是原子的,如果被检查的条件变量无变化则线程阻塞,等待条件变量变化信号
的唤醒。必须调用cv_init(9F)初始化条件变量,调用cv_destroy(9F)摧毁条件变量。

注意:条件变量例程类似SunOS 4.1中的sleep()和wakeup()例程。
代码举例 使用互斥锁和条件变量

————————————————————————–
static int xxread ( dev_t dev, struct uio * uiop, cred_t * credp )
{
struct xxstate * xsp;


mutex_enter( &xsp->mu );
while ( xsp->busy )
{
cv_wait( &xsp->cv, &xsp->mu );
}
xsp->busy = 1;
mutex_exit( &xsp->mu );
perform the data access
} /* end of xxread */

static u_int xxintr ( caddr_t arg )
{
struct xxstate * xsp = ( struct xxstate * )arg;

mutex_enter( &xsp->mu );
xsp->busy = 0;
cv_broadcast( &xsp->cv );
mutex_exit( &xsp->mu );
} /* end of xxintr */

3. 有一些关键词点击次数的文件,如何输出最多点击的一百个(当时应该回答,组织一个100个元素的最大堆)

 

4. 相交链表,如何找相交点(不能要标记)

   第一个头遍历到尾,知道他的长度;第二个头遍历到尾,知道他的长度。这样知道两截链表在交点前的长度,长的先走几步,然后一样长了,再轮流下走,就会相聚,相遇节点就是相交节点)

 

5. 有些文件,频繁访问在磁盘里头的,现在要放到内存中了。采用什么策略来决定哪些放到内存中?如果是一些url文件,放在内存后,如何快速的找到某个url的位置(采用字典序或者b树之类树状结构来组织)如何快速找到哪些文件太久没人访问了,把他替换出去?(再那一棵树,记录树里每个位置url的访问时间;同时,那个url树的节点,也有这个时间树的对应的位置信息。时间树采用最大堆组织。要替换出去时,就从树顶取走节点,并且从中获得这个节点在url树对应位置,把他从url树中取走。当url被访问时,由于url树节点有时间树的位置信息,所以也很快找到对应节点在时间树的位置,然后把他的访问时间更新,然后做堆调整,每次堆调整为logN)

 

6. c语言相关:内联函数的好处?非内联函数被调用的过程是怎么样的?

  int,short,char的struct,这几个数应该怎么放,内存小?怎么防止头文件被include多次?

 

7. 有没有什么问题想问的

8 linux 网络查看的命令

 

二面

1. 介绍一个项目

 

2. 2.5亿个int数,可能有相同的。统计出这里头不同的数有多少个?只有2g内存。

(2.5*1000 000 000 * 4 =1G)

统计数-用hash,key是数,value是1或0,标记是否出现。

如果key就是那个数,那么找一个数的时候,要遍历hash才知道有没有,慢(就是如果hash紧凑,慢)。

解决方案:把key作为连续的(就是hash是稀疏的,有个key值没有存在这2.5亿个数中),像数组下标一样,那么要访问第n个数,直接到第n个去看,复杂度是O(1)

但是,如果连续,2.5亿个数,范围很广,而每个key用int存,会很大量,内存不一定够。

解决方案:每个key用一位bit来标志。即数字1放在第一个bit上,数字2放在第二个bit上。看第n位在不在,就找一下第nbit1,还是0

具体方法:char a[] 数组。假设找3,那么33/8--0...3,所以在a[0]中,找第3bit,如果是0,就设置为1。最后看看a[]的二进制表示有多少个1就有多少个数

 

3. 海量数据,在mysql中,cpu占用率很高或机器运行很慢。如何解决?

1.show processlist,看哪个sql查询的多,建索引(问:建立联合索引时,要考虑什么,怎么建(哪个在前,哪个列在后?)

2.如果老是在拷贝到临时表,就改配置,把临时表内存改大些

3.还有什么方法:

1)分布式数据库 (问:如果你来设计分布式数据库,你会怎么设计?)

2)使用缓存   (问:如果缓存中的数据,被删除或跟新了,数据库怎么判断这个缓存的数据不能用了,是脏数据?)(不懂)

问:什么情况下cpu会高?(内存不足)为什么内存不足cpu会高(频繁io读写)

 

4. n个无序int,(有正有负),给一个数v,如何找出其中的a+b=v的两个数

(我的答案是:排序 O(nlogn),记录序列中,0,大于v,小于v的3位。

尝试最小的和最大的,最大不行,次大。。。,找到某个,加起来小于v了,停止

尝试次小的,从上次大头停止的位置开始尝试

---尝试范围两头不断缩小,复杂度为n)

 

5. 网络相册,一个人可以有多个相册,一个相册有多个图片,如何快速实现增删查移动等操作。web页面上,图片是翻页显示。

(我回答:数据库记录:usr_id, book_id, item_id, position。相片放在磁盘上,目录为position/usr_id/book_id/item_id

一次查两个操作:1)数据库查找2)根据位置取图片

 

如果用户提取某个相册的所有图片,先给他第一个相片和所有item_id列表。然后用户翻页了,在客户端通过javascript能够知道翻的是哪个item,把item_id,book_id, usr_id发给服务器,服务器根据这个到目录下去找)

(你这种设计会有什么问题?(答不上来。。。)(如果用户频繁翻页,那么服务器上会不断地在传输图片)(如何解决?)

 

第五题我想不出好办法,我觉得一般他们都show thumbnail

就是预览小图片不把原始图片show在页面上,点击后才能看单个图片

 

 

6. Unix系统里,一个简单的print helloworld的c程序,从./a.out执行到屏幕打印出来这句话,是什么过程

(1.读elf,会从相对地址,计算出各个symbol的在进程中的绝对地址。然后找到入口main函数

  1.用到std的库,所有有runtime load。

  2.然后是print调用的进栈

  3.然后是系统调用,当前进程被挂起。系统调用会调用驱动。。。(内核切换,用户态到内核态)

  4.内核处理完再唤醒当前进程。(切换)

 5.print调用完毕,退栈

 6.main函数退栈

问:哪个进程来调用的main?(不知道)

应该是当前运行a.out的这个和用户交互的shell作为父进程,然后父进程fork子进程,子进程和父进程一样,然后调用execv会load执行文件,和把参数传到main的堆栈中

 

7.socket编程,要注意什么问题

(服务器的serversocket的基本模型。

但是大量请求,会不能及时响应。所以要多线程。

一个监听线程,多个服务线程。服务线程一开始起来都阻塞在存放请求socket的tasklist上。wait

监听线程接受到client的socket,放入tasklist中,signal唤醒一个服务线程。服务线程处理它,并把它从list中移走

注意问题:tasklist的存放的请求socket是会被放和移走的,消费者生产者问题。所以要synchronized来互斥?)

 

三面

2. fread的过程(文件系统-内核。。。)

3. 主DB在接到数据更新后同步到后台DB,如何避免网络丢失之类的问题

(参考答案1:传的是sql语句,接到后回ack,如果主DB发现一段时间没有回,重发;其实TCP传输,就保证了不会漏数据,所以不会考虑这个问题的)

(参考答案2:每次传sql语句和当前版本号,然后后台DB会对比版本号是不是正确,发现落后就发数据请求。主DB保留每次版本号更新关联的sql语句)

4. N个bit,如和判断其中有多少个1.(时间复杂度小于N)

预存一个2的8次方大小的数组,每个数组值是,这个下标的数的二进制的1的个数,例如:

a[0]=0, a[1]=1, a[2]=1,a[3]=2....a[2^8-1]=7(以空间换时间)

 

然后一个byte一个byte的读,看看他的值,直接以这个值为下标去数组看他的1的个数

 

 

另一个方法:

 

while(v){

v &= (v-1);

num++;

}

 

1000 & 0111 = 0, 所以每&一次,不为0,说明有1个1,&到为0为止,num就是1的个数。复杂度为1的个数。

 

一个是 char str ="hello";sizeof(str)和strlen(str)为多少,还有一个是floata;将其和0做比较的if语句如何编写。

一个数据结构算法实现题:给定二叉树,写出计算该二叉树的高度的函数

给定二叉树,写出拷贝该二叉树的函数,返回拷贝后根节点值

给定字符串,内容为a-z的字符,其中有一个字符出现为奇数次,其他均为偶数次,找出出现奇数次的字符

tcp\ip协议三次握手

两道算法题:1)、从一个字符串中找出不出现重复字符的长度最长的子字符串

2)判断两个链表是否有相交

 

 

a[n], b[n]是排序好的数据,如何查找a[n]和b[n]合并后的中位数,即将a[n],b[n]放在一起重新排序后的中间那个数

堆和栈的区别,new和malloc之间的区别(运算符函数),什么时候用堆,什么时候用栈

 

 

 

第二个问题:两个排序的数组,怎么求交集。

这个会,我说两个数组同时遍历,相等的时候输出,小的下标++,他说恩,那你说说这个时间复杂度多少,这个我知道O(M+N),他接着问,现在这两个数组大小相差很大,应该怎么去改进算法,我想了一下,说用二分。他说恩这个可以,他又问,这样的时间复杂度是多少,我答:O(Mlog2N), 他接着问,在什么情况下,这种优化才有明显效果,现在假如我第一个数组的大小为10万个int ,那第二个多大才会有效果。晕,他给我一支笔,说你想想,我晕,那就算吧,第一种O(M+N),第二种是O(Mlog2N)算了一下,当N>16M的时候才有效果,Mlog2(100K) = M*(10+log2(100))=17M,17M<M+N,N>16M,期间还犯了个低级错误,把log2(100K)= log2 (1000)*log2(100),算了大概是60多,那哥们很差异,我才想到就改成上面的,他又问了,在实际中,我们这种算法在N》90M的时候才会有效果,问我为什么?我又晕,我说是不是因为第一种方法有可能在很早就结束了,他说我们做很多测试,这个是平均时间复杂度,我无语了,接着想,我说是不是因为二分查找出现太多找不到情况,说出口我就知道错了,二分查找最坏的情况就是log2N+1,他说不是,沉默了一会,我估计我一时半会想不出来,我就说:这个问题我估计短时间想不出来,那哥们给提示了,问我二维数组的二种遍历方式,按行和按列怎么实现,我说这个数据结构书上有讲,二维数组有两种存储方式,一种是按行,一种是按列,他说有按列存储的吗?怎么个存储方法,当时我没敢说,我说数据结构书上是这样说的。他没接着问这个,就问我按行遍历快,还是按列遍历快,我说按行,他说为什么,我说数组是顺序存储的,按列要计算地址,CPU寻址是需要时间的,这时我想到我上面题目的原因了。原来二分查找寻址的时候有开销。他又接着问,第一个数组和第二数组倍娄相差不是很大的时候怎么优化,假如说N=10M,我晕,真绝,我说应该给大的分块,他又问怎么个分块法,我先给我知道的东西说了一下,在数据结构中,分块查找一般是按照数组大小的开平方来决定的,不过对于我们这个问题,应该考虑到实际情况,想了一会,我说应该按它们之间倍数来分块,他说恩,那我们这个问题就到这。我晕,

第三个问题:智力题:100个球,我和你来拿,每人只能拿1-5之间的数目的球,你先拿,谁最后先拿完,谁就赢。歇菜了,当时头一大,没有思路,我还是说我想想,想了30秒,我说出自己的方案,我说最后让他给我剩5个以内的球,我就能赢,所以在95球让他最后拿完,于是说,我先拿5个,剩下的,他拿1个我就拿他的对5的补,结果应该有可能会赢,面试GG分析了一下不行,叫我再想,受不了,想了2-3分钟,期间也说了一二个想法,都给他否决了,然后我说,能不能给点提示,他说,你想赢,最后一个回合,你要给他留几个球,我想,说6个,我顿时感觉自己智障,只想自己一下给最后拿完,没想到给人下套,于是我告诉他我的答案,第一次我拿4个,然后你拿多少,我就拿你的个数对6的补,(每次都给你下套,赵大叔应该来拐他几回)。他说:恩OK,这个问题就到这。

第四个问题:一个int数组,问怎么找到这个数组中重复超过一半的数?

这个暑假在崇新通信做过,我说可以用STL吗,他说可以,我说那很简单,给出一个map<int,int>对里面的数组遍历一次,然后遍历一次map,只要map的second大于数组的一半,输出他的first域。他说你这个复杂度多少,我晕又是这个,我说O(2N),他说你这样的话,要用2M的空间开销,你能不能降低开销,我晕了,我想我能不能对数组排序,他说可以,我说那也很好做,我先排序,然后来统计一下里面重复的个数,这样就能做到,他说这是可行的,你要知道当N很大的时候,你的排序要多少时间复杂度,我说最少也是O(Nlog2N),他说,所以这方法不可行,还有没有其它方法,我晕,左思右想,找不到合适的,又用期待眼光看着他,说能不能给点提示(实在脸皮厚),不过可惜的是,他没看我一眼,对着电脑说你想这样的数在数组里面是个什么数,我说是众数,他说这是肯定的,他说应该也是中位数,我说当N很大M也不小,你这样假设不太对,那哥们没说什么,我猛然想到,一次不行,多几次应该差不多,我说了我的想法,我用几次二分,多找几回,如果,出现的数多,就拿这个数来做,哥们笑笑说,这个问题就到这。

 

 

输入一个字符串,要求找出字符串中最大子串的长度(如字符串abcd13agbf,当重复出现某个字符时,算一个子串,比如abcd13a或bcd13agb都是子串)。

 

 

 

【百度质量部笔试题】

第一部分:

1. 简述链表和数组的优缺点。

2. 给了一长串代码,说明函数实现的功能?执行函数打印的结果?优化的算法设计?

another_func()…

 

some_func()…

其实就是比较给定的字符串集合{“cafe”, “baidu”, “duiba”,”face”, “thisone”,”iseasy”}中是否存在有这样的字符串,它们包含的字符以及字符个数相同,出现顺序不必相同,找到并打印出来。

 

3. 纸牌的问题,具体题目太长了,我没有记下来,就是魔术师分别告诉观众一张牌的花色和点数,然后两位观众说几句话来判断这张牌到底是什么?

 

第二部分:

1. 二叉树的前序遍历算法,分别用递归和非递归的方式实现,要求写出可执行的代码。

 

2. 给定一个M*M的字符矩阵,给出了找到连续对角线字符串的方法,从左上到右下,从右上到左下,共有四种对角线字符串,(1)让你写出怎么在这个字符矩阵的对角线字符串中找到给定的子串,写出算法设计。(2)如果M*M矩阵超大,无法载入内存,怎么办呢?

 

3. 系统设计题:设计一个服务调度管理器,服务器接收数据包,数据包大小为32个字节,第一个字节是请求的优先级,后面31个字节是请求的命令,服务器根据客户端发来的命令,分配资源,完成相应的服务,然后将操作的结果返回给客户端,但是由于服务器资源有限,故服务器可以存储操作的结果,如果下次有同样的命令到来的时候,直接获取操作结果返回给客户端即可。

要求设计一个服务器调度管理器,满足以下调度条件:

1)同样条件下,请求次数多的请求首先获得服务,请求次数最大255

2)同样条件下,请求优先级高的请求首先获得服务,优先级等级最高16.

要做的是:

1)设计服务器的核心调度算法:

2)数据结构设计

3)如果服务器的记录容量是20万条,分析需要占用多大内存空间??

 

 

 

 

1.      字母序列O,T,T,F,有什么规律?请依据这个规律指出剩下的五个数,并说明其原因。

2. O(one),T(two),T(three),F(four),F(five),S(six),S(seven),E(eight),N(nine),T(ten)

3.       

2.1-16十六个数字分别填入十六格方框内,要求从左至右的数字是从小到大排列,从上至下的数字也是从小到大排列,问:有多少种排列方式。

4*4十六格方框中
左上第一个格只能为1  右下最后一格只能为16,余下2-15这些数字。我们从左上开始
STEP 1,最靠近第一格的(下方和右边)这两格,也只能从2和3里面选,所以2!
STEP 2,以此类推,位于填2和3的那两格的下方,方框对角线的上方的那三格从4、5和6里面选,所以是3!
STEP 3,同理由上得4! 3! 2!
STEP 4,相加得答案

 

3.医院,某人说:医护人员共16人,医生人数少于护士人数,男医生少于男护士,女护士少于男护士,至少一名女医生,问题:某人的性别及身份

4.电子商务的问题,是个老题,坛子里有过,就是问为什么宠物商品及化妆品的网上购物率为什么是增长最快的问题

5。同样是道老题,问易拉罐做成圆柱形的十个原因

6.一道类似运筹的题,就是看你如何做时间安排,说一个人5点30分刚运动完,口很渴,家里没水,女朋友6点左右要来家里吃饭,家里什么食材都没有;邻居拜托去接幼儿园小朋友,并在6点30左右来接孩子回家,孩子很小,必须有人照顾;距居住处最近的菜市场走路5分钟,路上没有杂货店等;幼儿园在相反方向,路途中有商店,步行10分钟;有自行车,但是车要是不确定放在哪里;约好在朋友下班后给朋友打电话。

7.一张比例为3600:1和一张比例为2000:1的标准地图,摆放好后,大的地图完全覆盖在小的地图上,问,是否存在一点,使用图钉在地图上按下去,可以使两张地图上的同意真实地点相重合?原因。

8.有好几个题让选择的,我选择的是策略题,如何设计一款盲人手机,功能,最好有图示;还有根据“红豆生南国,春来发几枝”、“锄禾日当午”“春晓”这几句诗设计主题网站“红豆网”“锄禾网”“春晓网”,网站的功能网,以及网站名称可以给网站带来的竞争优势(选择其一论述即可)

9.是否满意自己本次答卷,如不满意,论述原因

 

 

 

第一部分·简答

1·简述树的深度优先算法、广度优先算法,及非递归实现的特点。

深度优先搜索法是优先扩展尚未扩展的且具有最大深度的结点;广度优先搜索法是在扩展完第K层的结点以后才扩展K+1层的结点。主要不同点在于深度优先需要使用栈,广度优先使用队列FIFO。
  非递归实现要求程序自己设置栈来保存要用到的数据,与递归不同的是递归需要系统来完成数据和程序执行状态在栈中的保存。非递归可以减少数据的冗余以及系统设置栈带来的巨大开销。

2·在文件系统中,元数据(比如ext2中的inode)的基本作用是什么?ext2跟ext3的根本区别是什么?

记录数据的Modify,Access,Create times.以及记录数据的存放块区。并且通过元数据的加锁机制等可以保证数据的一致性。
  ext3是ext2的扩展,主要区别是ext3加入了日志系统。它允许以回写(writeback)预定(ordered),数据(data)三种方式记录日志,默认为预定。并默认在日志添满1/4,或某一个日志记时器超时时提交日志。

3·在web服务中,负载均衡的基本作用是什么?请举例你熟悉的一款负载均衡软件或者实现方案,简述它们的实现原理。(这题后半部分为开放性,我也没记多深,大概就这样)

由于系统服务访问量和带宽的暴增,服务器的TCP/IP协议栈,服务器系统的低效和处理器的低效便成为了瓶颈。因此负载均衡集群的出现将服务均匀地分配给提供同一种服务的各个服务器,从而降低单个服务器的负担。
  LVS(Linux Vitual Server):LVS采用GPL协议,可以自由开发。大致分为三层:
    1. 负载调度器:对外的前端机使用IPVS(IP负载均衡)软件,采用3种IP负载均衡技术和8种负载调度算法。其中负载均衡技术如直接路由法VS/DR,可以通过改写请求的MAC地址,将请求发送到真实的服务器,这样有效地提高了集群系统的伸缩性和吞吐量。8种调度算法如加权最少链接法,动态地将请求发送到目前链接最少的真实服务器上,并通过加权来优化算法,很好地提高性能。
    2.服务器池:通过增加服务器池的结点数目,往往性能会成线性的增长。有效地解决了服务的伸缩性。
    3. 共享存储:数据库或是网络文件系统,也有可能是分布式文件系统。数据库保证并发访问的一致性,静态数据可存在网络文件系统如NFS/CIFS中,如系统规模大,可以使用分布式文件系统存储。而且共享存储对于大多数情况下的读密集服务来讲可以提供大容量的cache,因此访问速度接近本地磁盘。

  另外还有基于HTTPS的安全系统管理WEB界面,便于系统管理员进行集群的管理和操作。

4·数据库事务的四大特性是什么?请你简单举例对一个完全不懂数据库的人解释这四个特性。投数据库管理员(DBA)必答。

事务的:原子性、一致性、分离性、持久性
(1) 原子性
  事务的原子性指的是,事务中包含的程序作为数据库的逻辑工作单位,它所做的对数据修改操作要么全部执行,要么完全不执行。这种特性称为原子性。
  事务的原子性要求,如果妑一个事务可看作是一个程序,它要么完整的被执行,要么完全不执垳。就是说事务的操纵序列或者完全应用到数据库或者完全不影响数据库。这种特性称为原子性。
假如用户在一个事务内完成了对数据库的更新,这时所有的更新对外部世界必须是可见的,或者完全没有更新。前者称事务已提交,后者称事务撤销(或流产)。DBMS必须确保由成功提交的事务完成的所洧操纵在数据库内有完全的反映,而失败的事务对数据库完全没有影响。

  (2) 一致性
事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。这种特性称为事务的一致性。假如数据库的状态满足所有的完整性约束,就说该数据库是一致的。
  一致性处理数据库中对所有语义约束的保护。假如数据库的状态满足所有的完整性约束,就说该数据库是一致的。例如,当数据库处于一致性状态S1时,对数据库执行一个事务,在事务执行期间假定数据库的状态是不一致的,当事务执行结束时,数据库处在一致性状态S2。

  (3) 分离性
  分离性栺并发的事务是相互隔离的。即一个事务内部的操作及正在操作的数据必须封锁起来,不被其它企图进行修改的事务看到。
分离性是DBMS针对并发事务间的冲突提供的安全保证。DBMS可以通过加锁在并发执行的事务间提供不同级别的分离。假如并发交叉执行的事务没有任何控制,操纵相同的共享对象的多个并发事务的执行可能引起异常凊况。
  DBMS可以在并发秇行的事务间提供不同级别的分离。分离的级别和并发事务的吞吐量之间存在反比关系。较多事务的可分离性可能会带来较高的冲突和较多的事务流产。流产的事务要消耗资源,这些资源必须要重新被访问。因此,确保高分离级别的DBMS需要更多的开销。

  (4)持久性
  持久性意味着当系统或介质发生故障时,确保巳提交事务的更新不能丢失。即一旦一个事务提交,DBMS保证它对数据库中数据的改变应该是永久性的,耐得住任何系统故障。持久性通过数据库备份和恢复来保证。
  持久性意味着当系统戓介质发生故障时,确保已提交事务的更新芣能丢失。即对已提交事务的更新能恢复。一旦一个事务被提交,DBMS必须保证提供适当的冗余,使其耐得住系统的故障。所以,持久性主要在于DBMS的恢复性能。

5·一个微型处理器,1KB内存和1MHz(每MHz运算次数为10^6),在这样的计算机上面运行程序(程序到该终止时会自动终止,不会出现死循环)最长能运行多长时间?你可以进行任何需要的假定。

1KB内存 ≈1000Byte≈ 8000bit 一共有2^8000个可能状态

 

所以答案为:2^8000/10^6

 

 

第二部分·算法和程序设计

1·int maxContinuNum(const char*inputstr,char * outputstr)

编写一段程序实现该函数,实现返回一个以“\0”结束的字符串中最长的数字串的长度,并把该数字子串的首地址赋给outputstr。不能使用任何库函数或已经存在的函数,如strlen。

例如:在字符串“abc123abcdef12345abcdefgh123456789”中,把该字符串的首地址赋给inputstr,返回9,outputstr指向字符串“123456789”的首地址。

 

 

 

第三部分·备份系统设计

(这题太长了,记住的不多,下面是大概的)

设计一个备份系统,要求符合三个备份场景,写出你的设计思路,框架模块设计,实现原理。

要求:1·该系统要能实现对多服务器备份工作(大概这样,还是。。)      

       2·该系统要具备很好容错性,不能因为多服务器中的一台出现故障儿导致整个备份工作不能进行。

       3·。。。

       4·。。。(这两点记不清了,不好意思)

       5·具有较强的扩展性,例如当服务器内存不够时,能灵活的添加内存。

 

扩展性是附加,在实现前面的要求后再考虑扩展性

 

备份场景           服务器              备份网络速度             备份开始时间

场景1             a1~a10                 10M/S               每天上午10点10分

场景2            a1,b1,c1,d1            30M/S               (忘了  - -!)

                     四台服务器

场景3            a1~a100                5M/S                 (也不大记得了。。)

 

 

 

第一题是

给出5个字母O T T F F 请推理并写出后5个字母,并说明原因。

 

第二题:

将一个正方形平分为16份,将1到16个数字填入其中要求 左比右大

上比下大问有多少中方法

 

第三题一家医院包括我在内有16名医护成员,以下的情况,包括我和不包括我对情况没有任何改变

具体的我给忘了...我有罪...

貌似是

护士多于医生

男医生多于男护士

男护士多于女护士

女医生至少有一个

 

问说话者的性别和职位

 

第四题

易拉罐设计为圆柱形的10个理由。

 

第五题:

1.5点半你回到家 大汗淋漓

2.你很渴,但是家里一滴水没有,需要重新烧水

3.刚交往2个周的恋人要拜访你家(6点左右),并且很希望尝尝你的手艺(冰箱里什么也没有)

4.1分钟前你的邻居(关系很好)打电话给你,拜托你去帮她去幼儿园接小孩(4岁),你答应了

幼儿园5点放学(幼儿园在你家东边,有800米远,步行需要10分钟,路上只有五金店和杂货店,买菜需要去菜市场,在

西边,从你家走要5分钟)

5.邻居6点半左右接孩子

6.你有一辆自行车,但不知道钥匙放在哪里

 

请问你怎么处理以上情况

 

想起来了还有一题是

第六题:美国今年的网络销售额涨幅达到20% 达到了9亿美元

其中宠物用品和化妆品的涨速最引人注目。

请分析

第七题:还有一个选答题

1. 你平时经常运用搜索引擎吗?你认为这些搜索引擎都有什么特点和不足?你认为网络引擎怎么做才能吸引网民的关注?

2.“红豆生南国,春来发几枝”“锄禾日当午,汗滴禾下土”等诗句

许多网站名来源于诗句,你认为“红豆”网,“锄禾”网分别可以设计成什么样的网站?

。。。。。

(我记得不是很清楚了,对不住大家)

第八题:

有两张标准世界地图,比例尺分别为1:200000和1:300000

将两张地图完全重合,然后拿一个图钉按下,你认为有可能按下的点为同一个真实地球上的点吗?

无论行还是不行,请简述理由

 

 

第一道题是设计个数据结构,树形结构,共有1000个节点,所有的叶子节点都在同一层,深度不超过10。满足

a)从节点A出发,方便找到深度为m的所有节点

b)从节点B出发,深度为k,方便找到从root到B的路径

请设计这种数据结构,并给出a,b两种情况的查询操作,及增加和删除操作

后边两小题忘了

第二题是简答题

1.简答DOM和SAX的异同,简答什么是SOAP。

2。简述你知道的设计模式和他们的应用场景。

第三题是算法题:

1.在一个x,y平面上有超过10000000个点,互不重合,应设计一个算法求出距离最短的3对点,并分析算法的效率.

2 有一个无序的实数序列x1,x2.....xn,请设计个算法在线性时间内找到相邻(不是序列相邻,而是在实数轴上相邻)两点间最大距离。

3 类似于灯泡开合问题,有1—60个灯泡全关,第一次所有1的倍数状态切换,第二次所有2的倍数状态切换。。。。。。。一直到60.求最后亮着的事哪几盏灯。(原题不是这样,但思路是一样的)

 

 

 

(1)简述链表和数组各自的优缺点。

(2)程序题,程序大概如下,a为一个字符串数组,字符串中每个字符都是介于'a'到'z'的小写字母,且字符串长度不超过20。

       (a)描述bbb函数的功能(可用一句话)。

       (b)假设N=7,且a={"cafe","baidu","recuit","thisone","iseasy","*******","*****"}(有两个字符不记得了....),写出输出结果。

       (c)写出bbb函数的时间复杂度(用N表示)。

       (d) 好像是bbb函数优化提高算法效率之类的。

       int aaa(char* b1,char* b2)

       {

            char g[26];

            int i;

            for(i=0;i<26;++i)

                 g=0;

            for(i=0;i<26;++i)

                 g[b1-'a']++;             

            for(i=0;i<26;++i)

                 g[b2-'a']--;

            for(i=0;i<26;++i)

           {

                  if(g)

                      return 0;

            }

                    return 1;

      }

 

 

       int bbb(char a[N][20])

      {

            int f[N];

            int i,j;

            for(i=0;i<N;i++)

                 f=0;

            for(i=0;i<N;i++)

           {

                   if(!f)

                        f=1;

                   printf("%s",a);

                   for(j=i+1;j<N;j++)

                  {

                        if(aaa(a,a[j]))

                        {

                              f[j]=1;

                             printf("%s",a[j]);

                         }

                        printf("\n");

                   }

            }

        }

 

(3)魔术师抽出16张牌,红心A,4,Q;黑桃J,8,4,7,2,3;草花K,4,Q,5,6;方块A,5。然后魔术师从中随意抽出一张牌,叫两观众上去,将点数告诉了观众甲,将花色告诉了观众乙。

     甲:我不知道这张牌。

     乙:我知道你不知道这张牌。

     甲:我知道这张牌了。

     乙:我也知道了。

     请问从这四句话中你能判断是哪一张牌?

 

(4)用递归和非递归的方法写出树的先序遍历,需为可执行的代码。

      给出结点定义

      class tree

      {

           public:

                    int data;

                    class tree *left, *right;

      };

      typedef class tree node;

      typedef node *bitree;

      为了方便coding,给出stock栈操作,push(PNode);pop();

 

 

(5)一个M*M的矩阵A,一个字符串数组S,比较S中的字符串是否在A中的连续对角线序列中出现。

      譬如一个4*4的矩阵                  1 2  3  4

                                  a  b c  d

                                  5  6 7  8

                                 e  f  g  h

      则其连续对角线从左算:1 2 a 5 b 3 4 c 6 e f 7 d 8 g h

                                或   1 a 2 3 b 5 e 6 c 4 d 7 f g 8 h

                           从右算:4 3 d 8 c2 1 b 7 h g 6 a 5 f e

                                或   4 d 3 2 c 8 h 7 b 1 a 6 g f 5 e

       (a)(b)两问,大概是写出优化高效的算法,不一定要程序,可用流程图或者文字描述,简述算法原理,计算时间复杂度。

 

(6)给出了一些条件,基于此要写一个任务管理调度器的核心算法,数据结构(前两问),第3问是啥不记得了。

 

 

 

 

已知有三男两女要用一艘船渡河这艘船一次只能栽两个人渡河

1:所有女士要求 不能有一男一女单独相处

2:由于每次只能有一个人划船 男士要求不能由同一个人连续划船

3:如果需要一个人单独划船 依次顺序为 阿特 本 考尔 请问最后一个划船的人是谁?

要求:要用最少的渡河次数渡河

 

 

 

 

1.树的深度优先、广度优先遍历算法,及非递归实现的特点。

 

2.给出一段代码,找出有错误或安全隐患的地方,及错误原因。

 

3. 假设有个迷你计算机,1KB内存,1MHz处理器(每秒可以改变10^6次状态)。所有能够在机器上运行且会运行到一定时候能够终止(没有死循环)的程序中,最长的运行时间。自己设置其他假设条件。

 

4. 一个大型项目中有很多组件,组件之间的编译有依赖,比如必须先编译完N1才能编译N2。设计快速算法,完成N>1000个组件的项目的编译过程,并给出算法复杂度。

 

5. 代码intmaxContinuNum(const char *inputstr, char *outputstr) 在以’\0'结尾的字符串中找连续最长的数字串,并返回其长度,并把该数字串赋给outputstr所知内存(不能用strlen之类的库函数)比如abc123abcd1234acbde123456789abcdefg,返回9,最长的数字串是123456789。

 

6. url地址 比如http://www.baidu.com/s?wd=baidu的属性,包括定长属性(比如其被系统发现的时间)和不定长属性(比如其描述)

实现一个系统

a.储存和维护100亿个url及其属性

b.实现url及其属性的增删改

c.查一个url是否在系统中并给出信息

d.快速选出一个站点下所有url

提示:因为数据量大,可能存储在多台计算机中

:因为数据量大,可能存储在多台计算机中。

分析:这是一道百度的笔试题,这道题比较难,笔者只能给出几个认识到的点。

  • 首先,这些url要经过partition分到X台机器中:考虑使用一个hash函数hash(hostname(url))url分配到X台机器中,这样做的目的:一是数据的分布式存储,二是同一个站点的所有url保存到同一台机器中。
  • 其次,每台机器应该如何组织这些数据?一种思路是用数据库的思路去解决,这里提供另外一种思路。考虑将url直接放在内存,接将url组织成树状结构,对于字符串来说,最长使用的是Trie tree,由于所占空间由最长url决定,在这里绝对不适用,再加上很多url拥有相同的属性(如路径等)这样,使用trie tree 的一个变种radix tree,相比会非常节省空间,并且不会影响效率。
  • 最后,给出了存储模型,上面的abcd四问该怎么回答,这里就不一一解答了。

 

 

 

1,深度优先  广度优先定义。它们非递归实现的特点

 

2,一个复数实部 虚部分别相乘求和的程序改错

 

3,一个有内存1KB  , 处理器速度 10^6/S

   最长计算时间

 

4, N个文件相互有倚赖(编译的时候) 设计一个算法,编译之

 

5,一个字符串中最长的数字子串

 

6,100忆个URL的存储,查找,删除,更新,添加

 

 

 

 

 

辨别url

用c语言实现一个revert函数

打印一定概率的随机数

蚂蚁们与木杆

找出数组中第k大小的数

两个已排序的整型数组求交集

计算最少操作次数

CPU的数据缓存问题

符合数A定义的数

用C语言实现memmove

排序长数组

编写C语言函数去掉所有ansi编码的字母和数字

两棵树是否相等的比较

求N!的尾部连续0的个数

基于数据库的通知发布系

 

 

 

1.推理:24个人,每人至少养一种宠物,养鸟、狗、鱼、猫的分别为13、5、10、9人,同时养鸟和狗的2人,同时养鸟和鱼、鸟和猫、鱼和猫的各为4人,养狗的既不养猫也不养鱼。问只养一种宠物的总共几人?同时养鸟鱼猫的几人?

2.找程序的错和不足:

int test(char *value,int value_len,intflag)

{

char temp_buf[BUF_SIZE];

sprintf(temp_buf,value);

char temp_new_buf=new char[value_len];

if(flag)

{

strcat(temp_buf,"flag is true");

printf(temp_buf);

return 1;

}

delete[] temp_new_buf;

return 0;

}

 

 

 

第一题:树的深度遍历,广度遍历,和非递归实现算法的特点。

第二题:一堆代码,找错误和潜在的危险。

第三题:一个有1kb内存和1mhz处理器的计算机在上面运行的程序的最长时间是多少

 

算法题目

 

1.      包编译依赖问题,设计算法,能够最快的完成包的编译

这个题终于明白了,确实是拓扑排序,根据遍历的时间排的,遍历用的是DFS

2.对输入的字符串能够从中找到最大连续数字的字符串

系统设计题目

 

百度最常出的题目,如何在100万url处理path、属性等等。

 

 

 

 

1.简述深度优先及广度优先遍历算法,并说明非递归实现的特点

2. 程序找错,一大段。

3. 假设有一台迷你计算机,1KB的内存,1MHZ的cpu,已知该计算机执行的程序可出现确定性终止(非死循环),问如何求得这台计算机上程序运行的最长时间,可以做出任何大胆的假设。

4. 大型软件有很多组件,编译时存在复杂的依赖关系,比如N1和N2存在依赖关系,要编译N1必须先编译N2,假设存在N<1000个组件,之间存在复杂的依赖关系,但不存在依赖环,问采用怎样的算法来构建编译规则,说明算法的复杂度。

5.写一个函数 intMaxContinuNum(const char *inputstr,char *outputstr)

找出一个字符串中最长的连续数字串,返回最长数字串的长度,并将最长字符串存入Outputstr指定的地址,

如, abcd1234abd123abcd123456789, 最长连续字符串为123456789,长度为9

6.有100亿个url,要求设计一个系统,能实现url的添加、删除、更新,并能查看url的内容

 

 

 

 

 

1 编写一个简单的支持正则表达式的字符串匹配函数,简单的正则表达式如下:

 

字符                     含义

c                        匹配字符c

.                         匹配任意一个字符

*                        若一个字符后紧跟*,则匹配0个或多个此字符

 

函数原型如下,参数regexp是待匹配的正则字符串,text是原始字符串。如果text中包含该正则串,函数返回1,否则返回0。建议先写明解题思路,再编码。

int match(const char* regexp, const char* text);

例如:regexp:        c*       text:ccccc   返回1

A*              Abcd     返回1

A*              bbcd     返回0

 

思路:处理较为简单的*和。的组合。假设不出现连续多个* , 也不会出现连续多个. 有可能出现的情况是:    . ; *;  .*;

1)如果,出现了一个。那么,主串下标i自加, 字串j自加。如果下一个字符是*,则找到*后面的字符,主串下标自加直到regexp[i]==字串*后面的字符为止。这时候求的是主穿中与*后面字符第一次匹配的情形,有可能后面还有匹配的情况,则在外面使用while循环,里面从主串和字串中相等的字符串后面的字符开始递归调用match函数如果后面的匹配了,又前面的已经匹配了,则整个匹配。否则,while循环寻找下个匹配的字符。循环执行。

2)如果出现了一个*, 说明这个*是单独出现的,若出现在.后面则在上面的1)中肯定处理完了。此处出现说明是单独出现,寻找*后面的字符,在主串中寻找第一个匹配的字符,另外要注意,匹配的字符前面的字符应该是相等的(*的缘故)。同1)由于可能存在多个匹配,使用while(i < strlen(regexp)) 并且循环里面利用递归match判断后面的时候匹配。

3)如果出现的既不是*有不是.那么肯定是正常字符,可以使用最笨的方法匹配,相等则i++,j++,不相等可以利用最笨的方法,i=i-j+1;j=0;也可以利用KMP算法不回溯。本人利用笨的了,呵呵。懒的把KMP弄上面来了。

算法如下:

#include <stdio.h>

 

int match(const char *regexp, const char*text)

{

int len1 = strlen(regexp);

int len2 = strlen(text);

 

int i=0;

int j=0;

int flag;

char ch, next;

while (i < len1 && j < len2)

{

ch = text[j];

if( ch == '.')

{

i++;

j++;

if( j >= len2)

{

printf("match\n");

return 1;

}

next = text[j];

 

if( next == '*')

{

j++;

if(j >= len2)

{

printf("match\n");

return 1;

}

ch = text[j];

 

while( i < len1)

{

while( regexp[i] != ch && i <len1)

{

i++;

}

if( ++j < len2)

{           

if(++i < len1)

{

flag = match(&regexp[i], &text[j]);

if(flag == 1)

{

printf("match\n");

return 1;

}

}

else

{

printf("mismatch\n");

return 0;

}

}

else

{

printf("match");

return 1;

}

}

}

}

else if( ch == '*')

{

ch = text[j-1];

j++;

if(j >= len2)

{

printf("match");

return 1;

}

 

next = text[j];

while( i < len1)

{

while( i<len1 && regexp[i] !=next)

{

if(regexp[i] != ch)

{

printf("mismatch");

return 0;

}

 

i++;

}

 

i++;

j++;

if( j >= len2)

{

printf("match");

return 1;

}

if( i>=len1 && (j +1 >= len2)&& ( text[j] == '*'))//用以匹配AA   A*A*等regexp短而text长并且  

// text最后一个字符是*的情况

{

printf("match");

return 1;

}

if(i < len1)

{

flag = match(&regexp[i], &text[j]);

if(flag == 1)

{

printf("match");

return 1;

}

}

else

{

printf("mismatch");

return 0;

}

}

}

else

{

if( regexp[i] == text[j])

{

i++;

j++;

if( j >= len2)

{

printf("match");

return 1;

}

 

}

else

{

i = i-j+1;

j=0;

}

}

}

}

 

 

 

int main()

{

const char *str1 = "AEGFBCDF";

const char *str2 = "A.*BCD*F";

 

int flag = match(str1, str2);

if(flag== 1)

printf("%s matches %s\n", str1,str2);

 

return 0;

}

 

实验:A* ,  Abcd

A*, bbcd

.A.*C   eABC 

A.*BCD*F   AEGFBCDF

均未出现错误。

解决该问题时,时间较为紧张,很多代码都存在隐患,并且没有添加注释,见谅,仅供参考!

另外,本人方法比较笨,希望高手指教!

十七道海量数据处理面试题与Bit-map详解

来源: 柳燕煌的日志

作者:小桥流水,redfox66,July。

文章性质:整理。

前言

    本博客内曾经整理过有关海量数据处理的10道面试题(十道海量数据处理面试题与十个方法大总结),此次除了重复了之前的10道面试题之后,重新多整理了7道。仅作各位参考,不作它用。

    同时,程序员编程艺术系列将重新开始创作,第十一章以后的部分题目来源将取自下文中的17道海量数据处理的面试题。因为,我们觉得,下文的每一道面试题都值得重新思考,重新深究与学习。再者,编程艺术系列的前十章也是这么来的。若您有任何问题或建议,欢迎不吝指正。谢谢。

第一部分、十五道海量数据处理面试题

1. 给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?

    方案1:可以估计每个文件安的大小为50G×64=320G,远远大于内存限制的4G。所以不可能将其完全加载到内存中处理。考虑采取分而治之的方法。

  1. 遍历文件a,对每个url求取,然后根据所取得的值将url分别存储到1000个小文件(记为)中。这样每个小文件的大约为300M。
  2. 遍历文件b,采取和a相同的方式将url分别存储到1000小文件中(记为)。这样处理后,所有可能相同的url都在对应的小文件()中,不对应的小文件不可能有相同的url。然后我们只要求出1000对小文件中相同的url即可。
  3. 求每对小文件中相同的url时,可以把其中一个小文件的url存储到hash_set中。然后遍历另一个小文件的每个url,看其是否在刚才构建的hash_set中,如果是,那么就是共同的url,存到文件里面就可以了。

    方案2:如果允许有一定的错误率,可以使用Bloom filter,4G内存大概可以表示340亿bit。将其中一个文件中的url使用Bloom filter映射为这340亿bit,然后挨个读取另外一个文件的url,检查是否与Bloom filter,如果是,那么该url应该是共同的url(注意会有一定的错误率)。

    读者反馈@crowgns:

  1. hash后要判断每个文件大小,如果hash分的不均衡有文件较大,还应继续hash分文件,换个hash算法第二次再分较大的文件,一直分到没有较大的文件为止。这样文件标号可以用A1-2表示(第一次hash编号为1,文件较大所以参加第二次hash,编号为2)
  2. 由 于1存在,第一次hash如果有大文件,不能用直接set的方法。建议对每个文件都先用字符串自然顺序排序,然后具有相同hash编号的(如都是1-3, 而不能a编号是1,b编号是1-1和1-2),可以直接从头到尾比较一遍。对于层级不一致的,如a1,b有1-1,1-2-1,1-2-2,层级浅的要和 层级深的每个文件都比较一次,才能确认每个相同的uri。

2. 有10个文件,每个文件1G,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。要求你按照query的频度排序。

方案1:

  1. 顺序读取10个文件,按照hash(query)%10的结果将query写入到另外10个文件(记为)中。这样新生成的文件每个的大小大约也1G(假设hash函数是随机的)。
  2. 找一台内存在2G左右的机器,依次对用hash_map(query, query_count)来统计每个query出现的次数。利用快速/堆/归并排序按照出现次数进行排序。将排序好的query和对应的query_cout输出到文件中。这样得到了10个排好序的文件(记为)。
  3. 对这10个文件进行归并排序(内排序与外排序相结合)。

方案2:

    一般query的总量是有限的,只是重复的次数比较多而已,可能对于所有的query,一次性就可以加入到内存了。这样,我们就可以采用trie树/hash_map等直接来统计每个query出现的次数,然后按出现次数做快速/堆/归并排序就可以了。

方案3:

    与方案1类似,但在做完hash,分成多个文件后,可以交给多个文件来处理,采用分布式的架构来处理(比如MapReduce),最后再进行合并。

3. 有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。

    方案1:顺序读文件中,对于每个词x,取,然后按照该值存到5000个小文件(记为)中。这样每个文件大概是200k左右。如果其中的有的文件超过了1M大小,还可以按照类似的方法继续往下分,知道分解得到的小文件的大小都不超过1M。对 每个小文件,统计每个文件中出现的词以及相应的频率(可以采用trie树/hash_map等),并取出出现频率最大的100个词(可以用含100个结点 的最小堆),并把100词及相应的频率存入文件,这样又得到了5000个文件。下一步就是把这5000个文件进行归并(类似与归并排序)的过程了。

4. 海量日志数据,提取出某日访问百度次数最多的那个IP。

    方案1:首先是这一天,并且是访问百度的日志中的IP取出来,逐个写入到一个大文件中。注意到IP是32位的,最多有2^32个IP。同样可以采用映射的方法,比如模1000,把整个大文件映射为1000个小文件,再找出每个小文中出现频率最大的IP(可以采用hash_map进行频率统计,然后再找出频 率最大的几个)及相应的频率。然后再在这1000个最大的IP中,找出那个频率最大的IP,即为所求。

5. 在2.5亿个整数中找出不重复的整数,内存不足以容纳这2.5亿个整数。

    方案1:采用2-Bitmap(每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义)进行,共需内存 2^32*2bit=1GB内存,还可以接受。然后扫描这2.5亿个整数,查看Bitmap中相对应位,如果是00变01,01变10,10保持不变。所描完事后,查看bitmap,把对应位是01的整数输出即可。

    方案2:也可采用上题类似的方法,进行划分小文件的方法。然后在小文件中找出不重复的整数,并排序。然后再进行归并,注意去除重复的元素。

6. 海量数据分布在100台电脑中,想个办法高效统计出这批数据的TOP10。

方案1:

  1. 在 每台电脑上求出TOP10,可以采用包含10个元素的堆完成(TOP10小,用最大堆,TOP10大,用最小堆)。比如求TOP10大,我们首先取前10 个元素调整成最小堆,如果发现,然后扫描后面的数据,并与堆顶元素比较,如果比堆顶元素大,那么用该元素替换堆顶,然后再调整为最小堆。最后堆中的元素就 是TOP10大。
  2. 求出每台电脑上的TOP10后,然后把这100台电脑上的TOP10组合起来,共1000个数据,再利用上面类似的方法求出TOP10就可以了。

(更多可以参考:第三章、寻找最小的k个数,以及第三章续、Top K算法问题的实现

7. 怎么在海量数据中找出重复次数最多的一个?

    方案1:先做hash,然后求模映射为小文件,求出每个小文件中重复次数最多的一个,并记录重复次数。然后找出上一步求出的数据中重复次数最多的一个就是所求(具体参考前面的题)。

8. 上千万或上亿数据(有重复),统计其中出现次数最多的钱N个数据。

    方案1:上千万或上亿的数据,现在的机器的内存应该能存下。所以考虑采用hash_map/搜索二叉树/红黑树等来进行统计次数。然后就是取出前N个出现次数最多的数据了,可以用第6题提到的堆机制完成。

9. 1000万字符串,其中有些是重复的,需要把重复的全部去掉,保留没有重复的字符串。请怎么设计和实现?

    方案1:这题用trie树比较合适,hash_map也应该能行。

10. 一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词,请给出思想,给出时间复杂度分析。

    方案1:这题是考虑时间效率。用trie树统计每个词出现的次数,时间复杂度是O(n*le)(le表示单词的平准长度)。然后是找出出现最频繁的前10 个词,可以用堆来实现,前面的题中已经讲到了,时间复杂度是O(n*lg10)。所以总的时间复杂度,是O(n*le)与O(n*lg10)中较大的哪一 个。

11. 一个文本文件,找出前10个经常出现的词,但这次文件比较长,说是上亿行或十亿行,总之无法一次读入内存,问最优解。

    方案1:首先根据用hash并求模,将文件分解为多个小文件,对于单个文件利用上题的方法求出每个文件件中10个最常出现的词。然后再进行归并处理,找出最终的10个最常出现的词。

12. 100w个数中找出最大的100个数。

  •     方案1:在前面的题中,我们已经提到了,用一个含100个元素的最小堆完成。复杂度为O(100w*lg100)。
  •     方案2:采用快速排序的思想,每次分割之后只考虑比轴大的一部分,知道比轴大的一部分在比100多的时候,采用传统排序算法排序,取前100个。复杂度为O(100w*100)。
  •     方案3:采用局部淘汰法。选取前100个元素,并排序,记为序列L。然后一次扫描剩余的元素x,与排好序的100个元素中最小的元素比,如果比这个最小的 要大,那么把这个最小的元素删除,并把x利用插入排序的思想,插入到序列L中。依次循环,知道扫描了所有的元素。复杂度为O(100w*100)。

13. 寻找热门查询:

搜 索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。假设目前有一千万个记录,这些查询串的重复读比较 高,虽然总数是1千万,但是如果去除重复和,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就越热门。请你统计最热门的10个查询串,要求使用的内存不能超过1G。

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

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

    方案1:采用trie树,关键字域存该查询串出现的次数,没有出现为0。最后用10个元素的最小推来对出现频率进行排序。

14. 一共有N个机器,每个机器上有N个数。每个机器最多存O(N)个数并对它们操作。如何找到N^2个数中的中数?

    方案1:先大体估计一下这些数的范围,比如这里假设这些数都是32位无符号整数(共有2^32个)。我们把0到2^32-1的整数划分为N个范围段,每个段包含(2^32)/N个整数。比如,第一个段位0到2^32/N-1,第二段为(2^32)/N到(2^32)/N-1,…,第N个段为(2^32)(N-1)/N到2^32-1。然后,扫描每个机器上的N个数,把属于第一个区段的数放到第一个机器上,属于第二个区段的数放到第二个机器上,…,属于第 N个区段的数放到第N个机器上。注意这个过程每个机器上存储的数应该是O(N)的。下面我们依次统计每个机器上数的个数,一次累加,直到找到第k个机器,在该机器上累加的数大于或等于(N^2)/2,而在第k-1个机器上的累加数小于(N^2)/2,并把这个数记为x。那么我们要找的中位数在第k个机器 中,排在第(N^2)/2-x位。然后我们对第k个机器的数排序,并找出第(N^2)/2-x个数,即为所求的中位数的复杂度是O(N^2)的。

    方案2:先对每台机器上的数进行排序。排好序后,我们采用归并排序的思想,将这N个机器上的数归并起来得到最终的排序。找到第(N^2)/2个便是所求。复杂度是O(N^2*lgN^2)的。

15. 最大间隙问题

给定n个实数,求着n个实数在实轴上向量2个数之间的最大差值,要求线性的时间算法。

方案1:最先想到的方法就是先对这n个数据进行排序,然后一遍扫描即可确定相邻的最大间隙。但该方法不能满足线性时间的要求。故采取如下方法:

  1. 找到n个数据中最大和最小数据max和min。
  2. 用n-2个点等分区间[min, max],即将[min, max]等分为n-1个区间(前闭后开区间),将这些区间看作桶,编号为,且桶i 的上界和桶i+1的下届相同,即每个桶的大小相同。每个桶的大小为:。实际上,这些桶的边界构成了一个等差数列(首项为min,公差为),且认为将min放入第一个桶,将max放入第n-1个桶。
  3. 将n个数放入n-1个桶中:将每个元素x[i] 分配到某个桶(编号为index),其中,并求出分到每个桶的最大最小数据。
  4. 最 大间隙:除最大最小数据max和min以外的n-2个数据放入n-1个桶中,由抽屉原理可知至少有一个桶是空的,又因为每个桶的大小相同,所以最大间隙不 会在同一桶中出现,一定是某个桶的上界和气候某个桶的下界之间隙,且该量筒之间的桶(即便好在该连个便好之间的桶)一定是空桶。也就是说,最大间隙在桶i 的上界和桶j的下界之间产生j>=i+1。一遍扫描即可完成。

16. 将多个集合合并成没有交集的集合

    给定一个字符串的集合,格式如:。要求将其中交集不为空的集合合并,要求合并完成的集合之间无交集,例如上例应输出。

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

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

(3) 请描述可能的改进。

    方案1:采用并查集。首先所有的字符串都在单独的并查集中。然后依扫描每个集合,顺序合并将两个相邻元素合并。例如,对于,首先查看aaa和bbb是否在同一个并查集中,如果不在,那么把它们所在的并查集合并,然后再看bbb和ccc是否在同一个并查集中,如果不在,那么也把 它们所在的并查集合并。接下来再扫描其他的集合,当所有的集合都扫描完了,并查集代表的集合便是所求。复杂度应该是O(NlgN)的。改进的话,首先可以 记录每个节点的根结点,改进查询。合并的时候,可以把大的和小的进行合,这样也减少复杂度。

17. 最大子序列与最大子矩阵问题

数组的最大子序列问题:给定一个数组,其中元素有正,也有负,找出其中一个连续子序列,使和最大。

    方案1:这个问题可以动态规划的思想解决。设b[i]表示以第i个元素a[i]结尾的最大子序列,那么显然。基于这一点可以很快用代码实现。

最大子矩阵问题:给定一个矩阵(二维数组),其中数据有大有小,请找一个子矩阵,使得子矩阵的和最大,并输出这个和。

    方案2:可以采用与最大子序列类似的思想来解决。如果我们确定了选择第i列和第j列之间的元素,那么在这个范围内,其实就是一个最大子序列问题。如何确定第i列和第j列可以词用暴搜的方法进行。

 

第二部分、海量数据处理之Bti-map详解

 

    Bloom Filter已在上一篇文章海量数据处理之Bloom Filter详解中予以详细阐述,本文接下来着重阐述Bit-map。有任何问题,欢迎不吝指正。

什么是Bit-map

    所谓的Bit-map就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素。由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省。

    如果说了这么多还没明白什么是Bit-map,那么我们来看一个具体的例子,假设我们要对0-7内的5个元素(4,7,2,5,3)排序(这里假设这些元素没有重复)。那么我们就可以采用Bit-map的方法来达到排序的目的。要表示8个数,我们就只需要8个Bit(1Bytes),首先我们开辟 1Byte的空间,将这些空间的所有Bit位都置为0(如下图:)

    然后遍历这5个元素,首先第一个元素是4,那么就把4对应的位置为1(可以这样操作 p+(i/8)|(0×01<<(i%8)) 当然了这里的操作涉及到Big-ending和Little-ending的情况,这里默认为Big-ending),因为是从零开始的,所以要把第五位 置为一(如下图):

      

然后再处理第二个元素7,将第八位置为1,,接着再处理第三个元素,一直到最后处理完所有的元素,将相应的位置为1,这时候的内存的Bit位的状态如下:

然后我们现在遍历一遍Bit区域,将该位是一的位的编号输出(2,3,4,5,7),这样就达到了排序的目的。下面的代码给出了一个BitMap的用法:排序。

view plain

  1. //定义每个Byte中有8个Bit位  
  2. #include <memory.h>  
  3. #define BYTESIZE 8  
  4. void SetBit(char *p, int posi)  
  5. {  
  6.     for(int i=0; i < (posi/BYTESIZE); i++)  
  7.     {  
  8.         p++;  
  9.     }  
  10.   
  11.     *p = *p|(0x01<<(posi%BYTESIZE));//将该Bit位赋值1  
  12.     return;  
  13. }  
  14.   
  15. void BitMapSortDemo()  
  16. {  
  17.     //为了简单起见,我们不考虑负数  
  18.     int num[] = {3,5,2,10,6,12,8,14,9};  
  19.   
  20.     //BufferLen这个值是根据待排序的数据中最大值确定的  
  21.     //待排序中的最大值是14,因此只需要2个Bytes(16个Bit)  
  22.     //就可以了。  
  23.     const int BufferLen = 2;  
  24.     char *pBuffer = new char[BufferLen];  
  25.   
  26.     //要将所有的Bit位置为0,否则结果不可预知。  
  27.     memset(pBuffer,0,BufferLen);  
  28.     for(int i=0;i<9;i++)  
  29.     {  
  30.         //首先将相应Bit位上置为1  
  31.         SetBit(pBuffer,num[i]);  
  32.     }  
  33.   
  34.     //输出排序结果  
  35.     for(int i=0;i<BufferLen;i++)//每次处理一个字节(Byte)  
  36.     {  
  37.         for(int j=0;j<BYTESIZE;j++)//处理该字节中的每个Bit位  
  38.         {  
  39.             //判断该位上是否是1,进行输出,这里的判断比较笨。  
  40.             //首先得到该第j位的掩码(0x01<<j),将内存区中的  
  41.             //位和此掩码作与操作。最后判断掩码是否和处理后的  
  42.             //结果相同  
  43.             if((*pBuffer&(0x01<<j)) == (0x01<<j))  
  44.             {  
  45.                 printf("%d ",i*BYTESIZE + j);  
  46.             }  
  47.         }  
  48.         pBuffer++;  
  49.     }  
  50. }  
  51.   
  52. int _tmain(int argc, _TCHAR* argv[])  
  53. {  
  54.     BitMapSortDemo();  
  55.     return 0;  
  56. }  

可进行数据的快速查找,判重,删除,一般来说数据范围是int的10倍以下

基本原理及要点

使用bit数组来表示某些元素是否存在,比如8位电话号码

扩展

Bloom filter可以看做是对bit-map的扩展(关于Bloom filter,请参见:海量数据处理之Bloom filter详解)。

问题实例

1)已知某个文件内包含一些电话号码,每个号码为8位数字,统计不同号码的个数。

    8位最多99 999 999,大概需要99m个bit,大概10几m字节的内存即可。 (可以理解为从0-99 999 999的数字,每个数字对应一个Bit位,所以只需要99M个Bit==1.2MBytes,这样,就用了小小的1.2M左右的内存表示了所有的8位数的 电话)

2)2.5亿个整数中找出不重复的整数的个数,内存空间不足以容纳这2.5亿个整数。

    将bit-map扩展一下,用2bit表示一个数即可,0表示未出现,1表示出现一次,2表示出现2次及以上,在遍历这些数的时候,如果对应位置的值是 0,则将其置为1;如果是1,将其置为2;如果是2,则保持不变。或者我们不用2bit来进行表示,我们用两个bit-map即可模拟实现这个2bit- map,都是一样的道理。


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值