笔试题及解释

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

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

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

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

更多阅读:

http://www.2cto.com/kf/200912/43500.html

初探编译器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[n] = online_num[n-1] + delta[n]。

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


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

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

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

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

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

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


腾讯笔试题:两个整数集合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只小白鼠。


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

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

解答: http://blog.csdn.net/heaven13483/article/details/7925621


腾讯笔试题:判断数字是否出现在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即可。



原文链接1,感谢原作者



1.C++模板的作用。 
将算法与具体对象分离,与类型无关,通用,节省精力

2.socket编程,如果client断电了,服务器如何快速知道???
有以下几个技术:
使用定时器(适合有数据流动的情况); 使用socket选项SO_KEEPALIVE(适合没有数据流动的情况); 
 

3.fork()一子进程程后 父进程癿全局变量能不能使用???
fork后子进程将会拥有父进程的几乎一切资源,父子进程的都各自有自己的全局变量。不能通用,不同于线程。对于线程,各个线程共享全局变量。

4.4G的long型整数中找到一个最大的,如何做????
我的想法是要找到最大的肯定要遍历所有的数的,而且不能将数据全部读入内存,可能不足。算法的时间复杂度肯定是O(n)
感觉就是遍历,比较。。。。还能怎么改进呢????
可以改进的地方,就是读入内存的时候,一次多读些。。。。
需要注意的就是每次从磁盘上尽量多读一些数到内存区,然后处理完之后再读入一批。减少IO次数,自然能够提高效率。而对于类快速排序方法,稍微要麻烦一些:分批读入,假设是M个数,然后从这M个数中选出n个最大的数缓存起来,直到所有的N个数都分批处理完之后,再将各批次缓存的n个数合并起来再进行一次类快速排序得到最终的n个最大的数就可以了。在运行过程中,如果缓存数太多,可以不断地将多个缓存合并,保留这些缓存中最大的n个数即可。由于类快速排序的时间复杂度是O(N),这样分批处理再合并的办法,依然有极大的可能会比堆和败者树更优。当然,在空间上会占用较多的内存。 

此题还有个变种,就是寻找K个最大或者最小的数。有以下几种算法:
容量为K的最大堆/最小堆,假设K可以装入内存;
如果N个数可以装入内存,且都小于MAX,那么可以开辟一个MAX大的数组,类似计数排序。。。从数组尾部扫描K个最大的数,头部扫描K个最小的数。
 

5.有千万个string在内存怎么高速查找,插入和删除???
对千万个string做hash,可以实现高速查找,找到了,插入和删除就很方便了。
关键是如何做hash,对string做hash,要减少碰撞频率。

在实际中,BKDRhash函数比较好
// BKDR Hash
unsigned int BKDRHash(char *str) 
{   unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
    unsigned inthash = 0;   
    while (*str)
    {
       hash = hash * seed + (*str++); 
    }   
    return (hash & 0x7FFFFFFF);
 }
6.tcp三次握手的过程,accept发生在三次握手哪个阶段?
三次握手:C----->SYN K
              S------>ACK K+1 SYN J
              C------->ACK J+1   
              DONE!
client 的 connect  引起3次握手
server 在socket, bind, listen后,阻塞在accept,三次握手完成后,accept返回一个fd,
因此accept发生在三次握手之后。。。。。。
7.Tcp流, udp的数据报,之间有什么区别,为什么TCP要叫做数据流?
TCP本身是面向连接的协议,S和C之间要使用TCP,必须先建立连接,数据就在该连接上流动,可以是双向的,没有边界。所以叫数据流 ,占系统资源多
UDP不是面向连接的,不存在建立连接,释放连接,每个数据包都是独立的包,有边界,一般不会合并。
TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证
8.
const的含义及实现机制,比如:const int i,是怎么做到i只可读的?
const指示对象为常量,只读。
实现机制:这些在编译期间完成,对于内置类型,如int, 编译器可能使用常数直接替换掉对此变量的引用。而对于结构体不一定。
看下面的例子:

const int j=100;    int *p=const_cast<int*>(&j);    *p=200;    cout<<j<<endl;    输出为什么是100呢?

cout<<*p<<endl; //输出是改过的200

编译器在优化代码时把cout<<j直接优化成cout<<100了,所以虽然p和&j的值一样,但cout<<j不再通过访问j的地址输出。(反汇编时也有看到直接把数字压栈push 100 )

这是因为,const型在压栈时,是使用的直接的数,就有点像C的#define a 100

对于非系统缺省类型,系统不知道怎么去直接替换,因此必须占据内存。

#include <iostream> using namespace std; struct A {    int i;    char ch;    A()    {        i = 100;        ch = 'S';    } }; int main() {    const A a;    const int i = 200;    int *p1 = (int*)&a.i;    int *p2 = (int*)&i;    *p1 = 1;    *p2 = 2; //   a.i = 200; //报错,左值不能为const    cout << a.i << " " << a.ch << endl;    cout << i << endl;    return 0; }

运行结果:

1 S 200
9.volatile的含义。
变量可能在编译器的控制或监控之外改变,告诉编译器不要优化该变量,如被系统时钟更新的变量。
10.OFFSETOF(s, m)的宏定义,s是结构类型,m是s的成员,求m在s中的偏移量。
#define OFFSETOF(s, m) size_t(&((s*)0)->m)
11.100亿个数,求最大的1万个数,并说出算法的时间复杂度。
小根堆来实现。注意是小根堆,
读入1万个数,然后做
时间复杂度是O(NlogK)
12.设计一个洗牌的算法,并说出算法的时间复杂度。
第一种: for i:=1 to n do swap(a[i], a[random(1,n)]);  // 凑合,但不是真正随机
第二种: for i:=1 to n do swap(a[i], a[random(i,n)]);   // 真正的随机算法
其中,random(a,b)函数用于返回一个从a到b(包括a和b)的随机整数。
至于怎么证明上两个算法,没想好。
算法复杂度是O(n。。。),要研究下random的实现。
 
13.socket在什么情况下可读?
1. 接收缓冲区有数据,一定可读
2. 对方正常关闭socket,也是可读
3. 对于侦听socket,有新连接到达也可读
4.socket有错误发生,且pending~~~
引用unp的一段话 第六章 6.3节   
A socket is ready for reading if any of the following four conditions is true:
a. The number of bytes of data in the socket receive buffer is greater than or 
     equal to the current size of the low-water mark for the socket receive buffer.
     A read operation on the socket will not block and will return a value greater than 0
b.  The read half of the connections is closed (i.e., A TCP connection that has received a FIN).
     A read operation on the socket will not block and will return 0 (i.e., EOF)
c. The socket is a listening socket and the number of completed connection is nonzero. 
    An accept on the listening socket will normally not block, although we will describe a   
d. A socket error is pending. A read operation on the socket will not block and will return
    an error (-1) with errno set to the specific error condition
14.流量控制与拥塞控制的区别,节点计算机怎样感知网络拥塞了???
拥塞控制是把整体看成一个处理对象的,流量控制是对单个的节点。
感知的手段应该不少,比如在TCP协议里,TCP报文的重传本身就可以作为拥塞的依据。依据这样的原理, 应该可以设计出很多手段。
 
15.C++虚函数是如何实现的???
使用虚函数表。 C++对象使用虚表, 如果是基类的实例,对应位置存放的是基类的函数指针;如果是继承类,对应位置存放的是继承类的函数指针(如果在继承类有实现)。所以 ,当使用基类指针调用对象方法时,也会根据具体的实例,调用到继承类的方法。 
 
16.C++的虚函数有什么作用? ??
虚函数作用是实现多态,
更重要的,虚函数其实是实现封装,使得使用者不需要关心实现的细节。
在很多设计模式中都是这样用法,例如Factory、Bridge、Strategy模式。 
17. 非阻塞connect()如何实现? ??
将socket设置成non-blocking,操作方法同非阻塞read()、write();
18. 以下代码输出结果:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("call execl"); 
sleep(1); 
execl("/bin/sh", "", NULL); 
printf("error!\n");
}
本题考标准IO缓冲,标准出错是不带缓缓冲的。
如若是涉及终端设备的其他流,则他们是行缓冲的;否则是全缓冲的。

printf是标准IO的一个,格式化打印到标准输出,在这里是行缓冲,那么没有遇到换行符也就是‘\n’或者没有强制flush, 则不会输出。
execl是创建新的可执行程序映像,一旦成功就不会返回了,只有在出错的情况会返回1.
所以以上的程序没有打印printf的内容,直接执行/bin/sh,输出为
$

若是代码改为以下:
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    printf("call execl\n");
    /*fprintf(stderr, "%s", "call execl");*/
    sleep(1);
    execl("/bin/sh", "", NULL);
    printf("error!\n");

    return 0;
}
则输出为:
call execl
$

若改为:
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    /*printf("call execl\n");*/
    fprintf(stderr, "%s", "call execl");       // 标准错误,不缓冲
    sleep(1);
    execl("/bin/sh", "", NULL);
    printf("error!\n");

    return 0;
}
则输出为:
call execl$

若改为:
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    /*printf("call execl\n");*/
    fprintf(stdout, "%s", "call execl");     // stdout行缓冲
    sleep(1);
    execl("/bin/sh", "", NULL);
    printf("error!\n");

    return 0;
}
则输出为
$

19. TCP通讯中,select到读事件,但是读到的数据量是0,为什么,如何解决????
select 返回0代表超时。select出错返回-1。

select到读事件,但是读到的数据量为0,说明对方已经关闭了socket的读端。本端关闭读即可。

当select出错时,会将接口置为可读又可写。这时就要通过判断select的返回值为-1来区分。

20.  给出float与“零值”比较的 if 语句(假设变量名为var)???
const float EPSINON = 0.00001;
  if ((x >= - EPSINON) && (x <= EPSINON)

浮点数在内存中的存贮机制和整型数不同,有舍入误差在计算机中用以近似表示任意某个实数。具体的说,这个实数由一个整数或定点数(即尾数)乘以某个基数(计算机中通常是2)的整数次幂得到,这种表示方法类似于基数为10的科学记数法。
  所以浮点数在运算过成功运算通常伴随着因为无法精确表示而进行的近似或舍入。但是这种设计的好处是可以在固定的长度上存储更大范围的数。
  例如,一个指数范围为±4的4位十进制浮点数可以用来表示43210,4.321或0.0004321,但是没有足够的精度来表示432.123和43212.3(必须近似为432.1和43210)。当然,实际使用的位数通常远大于4。  
  所以浮点数不能够判断相等像 if(x==0)的这样的编码是不总是正确的,我们在判断浮点数相等时,推荐用范围来确定,若x在某一范围内,我们就认为相等,至于范围怎么定义,要看实际情况而已了,float,和double 各有不同
  所以const float EPSINON = 0.00001;  
  if ((x >= - EPSINON) && (x <= EPSINON) 这样判断是可取的
  至于为什么取0.00001,可以自己按实际情况定义

原文链接2,感谢原作者


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值