您的位置:首页 > 职场人生

【面试专题】腾讯PHP实习生笔试题目及答案解析

2012-04-04 18:16 645 查看
http://wt.guolairen.com/20110517/n552112.shtml


腾讯笔试题:const的含义及实现机制分析:

  const的含义及实现机制,比如:const int i,是怎么做到i只可读的?

  const用来说明所定义的变量是只读的。

  这些在编译期间完成,编译器可能使用常数直接替换掉对此变量的引用。

  初探编译器static、const之实现原理

  腾讯笔试题:买200返100优惠券,实际上折扣是多少?

  到商店里买200的商品返还100优惠券(可以在本商店代替现金)。请问实际上折扣是多少?

  分析:

  由于优惠券可以代替现金,所以可以使用200元优惠券买东西,然后还可以获得100元的优惠券。

  假设开始时花了x元,那么可以买到 x + x/2 + x/4 + …的东西。所以实际上折扣是50%.(当然,大部分时候很难一直兑换下去,所以50%是折扣的上限)

  如果使用优惠券买东西不能获得新的优惠券,那么

  总过花去了200元,可以买到200+100元的商品,所以实际折扣为 200/300 = 67%.

  腾讯笔试题:tcp三次握手的过程,accept发生在三次握手哪个阶段?

  分析:

  accept发生在三次握手之后。

  第一次握手:客户端发送syn包(syn=j)到服务器。

  第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个ASK包(ask=k)。

  第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1)。

  三次握手完成后,客户端和服务器就建立了tcp连接。这时可以调用accept函数获得此连接。

  腾讯笔试题:用UDP协议通讯时怎样得知目标机是否获得了数据包

  用UDP协议通讯时怎样得知目标机是否获得了数据包?

  分析:

  可以在每个数据包中插入一个唯一的ID,比如timestamp或者递增的int。

  发送方在发送数据时将此ID和发送时间记录在本地。

  接收方在收到数据后将ID再发给发送方作为回应。

  发送方如果收到回应,则知道接收方已经收到相应的数据包;如果在指定时间内没有收到回应,则数据包可能丢失,需要重复上面的过程重新发送一次,直到确定对方收到。

  腾讯笔试题:统计论坛在线人数分布

  求一个论坛的在线人数,假设有一个论坛,其注册ID有两亿个,每个ID从登陆到退出会向一个日志文件中记下登陆时间和退出时间,要求写一个算法统计一天中论坛的用户在线分布,取样粒度为秒。

  分析:

  一天总共有 3600*24 = 86400秒。

  定义一个长度为86400的整数数组int delta[86400],每个整数对应这一秒的人数变化值,可能为正也可能为负。开始时将数组元素都初始化为0。

  然后依次读入每个用户的登录时间和退出时间,将与登录时间对应的整数值加1,将与退出时间对应的整数值减1。

  这样处理一遍后数组中存储了每秒中的人数变化情况。

  定义另外一个长度为86400的整数数组int online_num[86400],每个整数对应这一秒的论坛在线人数。

  假设一天开始时论坛在线人数为0,则第1秒的人数online_num[0] = delta[0]。第n+1秒的人数online_num
= online_num[n-1] + delta


  这样我们就获得了一天中任意时间的在线人数。

  腾讯笔试题:从10G个数中找到中数

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

  分析:

  不妨假设10G个整数是64bit的。

  2G内存可以存放256M个64bit整数。

  我们可以将64bit的整数空间平均分成256M个取值范围,用2G的内存对每个取值范围内出现整数个数进行统计。这样遍历一边10G整数后,我们便知道中数在那个范围内出现,以及这个范围内总共出现了多少个整数。

  如果中数所在范围出现的整数比较少,我们就可以对这个范围内的整数进行排序,找到中数。如果这个范围内出现的整数比较多,我们还可以采用同样的方法将此范围再次分成多个更小的范围(256M=2^28,所以最多需要3次就可以将此范围缩小到1,也就找到了中数)。

详细解释:

网上给出的一个答案是采用桶的思想,把数据映射到很多桶,再取中间桶找中位数,整个过程下来要扫描两遍数据。但其关键是对这海量的数大小有预先限制,那现在假设这些数的大小无法预先限制,而且10G个的整数,或者说题目改为每次只能去五分之一的数据拿到内存进行排序,那又该如何去解答这道题呢?

思考中。。。

 

附网上搜到的一个方法:

关于中位数:数据排序后,位置在最中间的数值。即将数据分成两部分,一部分大于该数值,一部分小于该数值。中位数的位置:当样本数为奇数时,中位数=(N+1)/2 ; 当样本数为偶数时,中位数为N/2与1+N/2的均值(那么10G个数的中位数,就第5G大的数与第5G+1大的数的均值了)。

分析:明显是一道工程性很强的题目,和一般的查找中位数的题目有几点不同。
1. 原数据不能读进内存,不然可以用快速选择,如果数的范围合适的话还可以考虑桶排序或者计数排序,但这里假设是32位整数,仍有4G种取值,需要一个16G大小的数组来计数。

2. 若看成从N个数中找出第K大的数,如果K个数可以读进内存,可以利用最小或最大堆,但这里K=N/2,有5G个数,仍然不能读进内存。

3. 接上,对于N个数和K个数都不能一次读进内存的情况,《编程之美》里给出一个方案:设k<K,且k个数可以完全读进内存,那么先构建k个数的堆,先找出第0到k大的数,再扫描一遍数组找出第k+1到2k的数,再扫描直到找出第K个数。虽然每次时间大约是nlog(k),但需要扫描ceil(K/k)次,这里要扫描5次。

解法:首先假设是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.以上方法只要读两遍整数,对每个整数也只是常数时间的操作,总体来说是线性时间。

2. 考虑其他情况。

若是有符号的整数,只需改变映射即可。若是64为整数,则增加每个区段的范围,那么在第二次读数时,要考虑更多的计数。若过某个计数溢出,那么可认定所在的区段或代表整数为所求,这里只需做好相应的处理。噢,忘了还要找第5G+1大的数了,相信有了以上的成果,找到这个数也不难了吧。

3. 时空权衡。

花费256M个区段也许只是恰好配合2GB的内存(其实也不是,呵呵)。可以增大区段范围,减少区段数目,节省一些内存,虽然增加第二部分的对单个数值的计数,但第一部分对每个区段的计数加快了(总体改变??待测)。

4. 映射时尽量用位操作,由于每个区段的起点都是2的整数幂,映射起来也很方便。

引用2:http://hi.baidu.com/mcgrady32303/blog/item/5a61cd08691c29d03bc763c5.html

腾讯的一道面试题:(与百度相似,可惜昨天百度死在这方面了)////

在一个文件中有 10G 个整数,乱序排列,要求找出中位数。内存限制为 2G。只写出思路即可。

答案:
1, 把整数分成256M段,每段可以用64位整数保存该段数据个数,256M*8 = 2G内存,先清0 
2,读10G整数,把整数映射到256M段中,增加相应段的记数 
3,扫描256M段的记数,找到中位数的段和中位数的段前面所有段的记数,可以把其他段的内存释放 
4,因中位数段的可能整数取值已经比较小(如果是32bit整数,当然如果是64bit整数的话,可以再次分段),对每个整数做一个记数,再读一次10G整数,只读取中位数段对应的整数,并设置记数。 
5,对新的记数扫描一次,即可找到中位数。 
如果是32bit整数,读10G整数2次,扫描256M记数一次,后一次记数因数量很小,可以忽略不记(设是32bit整数,按无符号整数处理 
整数分成256M段? 整数范围是0 - 2^32 - 1 一共有4G种取值,4G/256M = 16,每16个数算一段 0-15是1段,16-31是一段,... 
整数映射到256M段中? 如果整数是0-15,则增加第一段记数,如果整数是16-31,则增加第二段记数,... 

其实可以不用分256M段,可以分的段数少一写,这样在扫描记数段时会快一些,还能节省一些内存)

引用3:还是给个伪代码吧

  腾讯笔试题:两个整数集合A和B,求其交集

  两个整数集合A和B,求其交集。

  分析:

  1. 读取整数集合A中的整数,将读到的整数插入到map中,并将对应的值设为1。

  2. 读取整数集合B中的整数,如果该整数在map中并且值为1,则将此数加入到交集当中,并将在map中的对应值改为2。

通过更改map中的值,避免了将同样的值输出两次。

  腾讯笔试题:找出1到10w中没有出现的两个数字

  分析:

  有1到10w这10w个数,去除2个并打乱次序,如何找出那两个数?

  申请10w个bit的空间,每个bit代表一个数字是否出现过。

  开始时将这10w个bit都初始化为0,表示所有数字都没有出现过。

  然后依次读入已经打乱循序的数字,并将对应的bit设为1。

  当处理完所有数字后,根据为0的bit得出没有出现的数字。

  首先计算1到10w的和,平方和。

  然后计算给定数字的和,平方和。

  两次的到的数字相减,可以得到这两个数字的和,平方和。

  所以我们有

  x + y = n

  x^2 + y^2 = m

  解方程可以得到x和y的值。

  腾讯笔试题:需要多少只小白鼠才能在24小时内找到毒药

  有1000瓶水,其中有一瓶有毒,小白鼠只要尝一点带毒的水24小时后就会死亡,至少要多少只小白鼠才能在24小时时鉴别出那瓶水有毒?

  分析:

  最容易想到的就是用1000只小白鼠,每只喝一瓶。但显然这不是最好答案。

  既然每只小白鼠喝一瓶不是最好答案,那就应该每只小白鼠喝多瓶。那每只应该喝多少瓶呢?

  首先让我们换种问法,如果有x只小白鼠,那么24小时内可以从多少瓶水中找出那瓶有毒的?

  由于每只小白鼠都只有死或者活这两种结果,所以x只小白鼠最大可以表示2^x种结果。如果让每种结果都对应到某瓶水有毒,那么也就可以从2^x瓶水中找到有毒的那瓶水。那如何来实现这种对应关系呢?

  第一只小白鼠喝第1到2^(x-1)瓶,第二只小白鼠喝第1到第2^(x-2)和第2^(x-1)+1到第2^(x-1) + 2^(x-2)瓶….以此类推。

  回到此题,总过1000瓶水,所以需要最少10只小白鼠。

更详细解释:http://blog.csdn.net/samuelltk/article/details/6901191

由题可知:由于20小时后才能知道小狗是否中毒,而且中毒的时间其实是无法精确到某一具体时间点或较短时间段的,所以每隔一段时间给狗吃药,根据20小时后记录小狗的发病时间来推算有毒药水的方法被我直接否定。而且其他所有拿细分时间段做文章的解题思路也一并摒弃。

因为那些方法除了可操作性几乎没有外,还有一种必然出局的理由就是每个人都会想到它,这就无法达到出题者测试应聘者能力的目的。因此,我觉得固守时间段思路的应聘者很难不被淘汰。

确定了思考角度,我所面临的难点就是如何将10只小狗和1000瓶药水建立某种联系,而这种联系还要受24-20=4小时的制约。

我所能想到的是将药水以某种形式交叉混合,然后喂给小狗,最终通过分析中毒小狗的数量和次序来确定有毒药水。

但是思前想后,最终我还是没能理出具体头绪,无奈只好求助于百度了。

找到题目出处很简单,当我看到原帖第6楼网友“OO”回复的答案后,我彻底拜服了,也自此绝了进腾讯等大公司的念想。

-=================================================================-

下面请看网友“OO”的解法:

把狗从0-9编号;

把药水按1-1000编号;

把药水编号按二进制,如果第i位(因为最大1000,所以bit位为0-9)bit位为1,则分给编号为i的狗狗喝;

最后得一二进制数,如果编号为i的狗狗死了,该数的第i bit位为1,该数就是有毒的药水编号。

他说的比较专业,下面我用实例给解析一下:

用 0、1、2、3、4、5、6、7、8、9 给小狗编号;

而药水按1-1000编号;

我们把每瓶药水的编号转换为二进制数,由于2的10次方=1024,所以我们将二进制数定为有10个数位,如:

1=0000000001

13=0000001101

214=0011010110

对二进制转换不熟悉的朋友可以用“开始-程序-附件-计算器-查看-科学型”来轻松转换。

这样转换以后,每个药水编号的二进制数的每一位都分别对应一只小狗;

我们定义每瓶药水要喂给其二进制编号位数为“1”的那位对应的小狗喝;

由于2的10次方=1024>1000,所以这些二进制编号组合都是唯一的;

当我们用不到4小时的时间将1000瓶药水分别喂给相应的小狗喝后,就可以去看看书,上上网,听听歌来打发剩下的20小时;

20小时候,在一个合理的药效发作时间后,我们统计有中毒症状小狗的编号,中毒的定为“1”,正常的定为“0”;

然后依照编号顺序排列,我们就可以得到一个10位的二进制数,而将这个二进制数再转换为十进制数后,这个数值就是有毒的药水的编号了;

例如,最终结果是编号为 2、4、6、7、9 的小狗有中毒症状,我们就将一个十位二进制数的2、4、6、7、9位设为“1”,其余各位设为“0”,即:0010101101;

而0010101101对应的十进制数=173,所以第173瓶药水就是有毒药水!

当然,如果都无毒,10只小狗就会都是活蹦乱跳的。

-=================================================================-

相信通过上面的解释,大家基本上都能理解这个解题思想的过程了吧。

回过头来反思为什么老王没能想出这么具体的解法呢?

最主要的一点还是思想不够活,没能将早就学过的计算机知识应用到实际解题过程中,这也就决定了我和OO等高手之间的差距。

介绍这种解题方法当然不等于没有其他更好的解法,只是我觉得这种解法就是出题者想要达成的目的。

而且在我看来,其他类似时间分块方法的可操作性和实现的科学性,照这个方法也确实是差的太多。

不过有一种现象很有趣,在原帖中,OO在第6楼就发布了他的解法,但下面还有数十上百个回帖在积极地发表和探讨各种漏洞百出的解法。看来人的思维的确很复杂,创新思想和求胜心理使很多人怀疑一个已经很不错的结论。不过我倒觉得适时肯定别人的成果并消化掉对自己的经验积累也很有用。

  腾讯笔试题:根据上排的数填写下排的数,并满足要求。

  根据上排给出十个数,在其下排填出对应的十个数, 要求下排每个数都是上排对应位置的数在下排出现的次数。上排的数:0,1,2,3,4,5,6,7,8,9。

  腾讯笔试题:判断数字是否出现在40亿个数中?

  给40亿个不重复的unsigned int的整数,没排过序的,然后再给几个数,如何快速判断这几个数是否在那40亿个数当中?

  分析:

  unsigned int 的取值范围是0到2^32-1。我们可以申请连续的2^32/8=512M的内存,用每一个bit对应一个unsigned int数字。首先将512M内存都初始化为0,然后每处理一个数字就将其对应的bit设置为1。当需要查询时,直接找到对应bit,看其值是0还是1即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息