2011-2012年腾讯,创新工场,淘宝,百度,阿里,迅雷。网易游戏校园招聘面试题集锦(1-25题含答案)

时间:2021-04-25 18:49:38
2011-2012年腾讯,创新工场,淘宝,百度,阿里,迅雷。网易游戏校园招聘面试题集锦(1-25题含答案)又是一年招聘季,小鸟我也在本季参加招聘,所以特在网上和群里面这里去年和今年的面试题,以备战招聘,有些题可能答案有问题,希望大家分享自己的答案和意见,也可以留言提供一些面试题,谢谢大家了。1.五只猴子分桃。半夜,第一只猴子先起来,它把桃分成了相等的五堆,多出一只。于是,它吃掉了一个,拿走了一堆; 第二只猴子起来一看,只有四堆桃。于是把四堆合在一起,分成相等的五堆,又多出一个。于是,它也吃掉了一个,拿走了一堆;.....其他几只猴子也都是 这样分的。问:这堆桃至少有多少个?参考答案:先给这堆桃子加上4个,设此时共有X个桃子,最后剩下a个桃子.这样: 第一只猴子分完后还剩:(1-1/5)X=(4/5)X; 第二只猴子分完后还剩:(1-1/5)2X;第三只猴子分完后还剩:(1-1/5)3X;第四只猴子分完后还剩:(1-1/5)4X;第五只猴子分完后还剩:(1-1/5)5X=(1024/3125)X;得:a=(1024/3125)X;要使a为整数,X最小取3125.减去加上的4个,所以,这堆桃子最少有3121个。2.已知有个rand7()的函数,返回1到7随机自然数,让利用这个rand7()构造rand10() 随机1~10。(参考答案:这题主要考的是对概率的理解。程序关键是要算出rand10,1到10,十个数字出现的考虑都为10%.根据排列组合,连续算两次rand7出现的组合数是7*7=49,这49种组合每一种出现考虑是相同的。怎么从49平均概率的转换为1到10呢?方法是:1.rand7执行两次,出来的数为a1.a2.2.如果a1*7+a2<40,b=(a1*7+a2)/10+1,如果a1*7*a2>=40,重复第一步)。参考代码如下所示: 01.int rand7()  02.{  03.  return rand()%7+1;  04.}  05.  06.int rand10()  07.{  08.  int a71,a72,a10;  09.  do   10.  {  11.    a71= rand7()-1;  12.    a72 = rand7()-1;  13.    a10 = a71 *7 + a72;  14.  } while (a10>= 40);  15.  return (a71*7+a72)/4+1;  16.}  3.如果两个字符串的字符一样,但是顺序不一样,被认为是兄弟字符串,问如何在迅速匹配兄弟字符串(如,bad和adb就是兄弟字符串)。01./* 02.如果两个字符串的字符一样,但是顺序不一样,被认为是兄弟字符串, 03.问如何在迅速匹配兄弟字符串(如,bad和adb就是兄弟字符串)。 04.*/  05.#include <iostream>  06.using namespace std;  07.  08.int isBroStr(char *str1, char *str2)  09.{  10.    int a[26 * 2] = {0};  11.    int i, strLen;  12.      13.    if (!str1 && !str2)  14.        return 1;  15.    else if (!str1 || !str2)  16.        return 0;  17.    else  18.    {  19.        if(strlen(str1) != strlen(str2))  20.            return 0;  21.        strLen = strlen(str1);  22.        for(i = 0; i < strLen; i++)  23.        {  24.            ++a[str1[i] - 'A'];  25.            --a[str2[i] - 'A'];  26.        }  27.        for(i = 0; i < 26 * 2; i++)  28.            if (a[i])  29.                return 0;  30.        return 1;  31.    }          32.}  33.  34.int main()  35.{  36.    char *str1 = "asdfaabAAB";  37.    char *str2 = "asdfAABaab";  38.    if (isBroStr(str1, str2))  39.        cout << " String 1 and String 2 are brothers!" << endl;  40.    else  41.        cout << " String 1 and String 2 are not brothers!" << endl;  42.    system("PAUSE");  43.    return 0;  44.}  4.要求设计一个DNS的Cache结构,要求能够满足每秒5000以上的查询,满足IP数据的快速插入,查询的速度要快每秒5000的查询不算高啊,最土的方法使用MySQL+Memcached架构应该都能满足吧?
数据结构建议以域名的md5值为主键来存储,值可以只存储目标IP就行。Memcached用户支撑前端查询,MySQL用户存储数据,还要看总书量会有多大,如果不是特别大,直接使用MyISAM引擎来存储就行,更新插入都非常快,如果超千万,可以使用InnoDB来存储,每次有新数据插入时直接使用replace into table就行,Memcached数据的更新直接使用set。
Memcached随便用得好些,每秒上万次的get是容易达到的,MySQL你别小看,在有的测试里,以主键查询的测试,一台普通的服务器上,MySQL/InnoDB 5.1服务器上获得了750000+QPS的成绩。5.淘宝面试题:有一个一亿节点的树,现在已知两个点,找这两个点的共同的祖先。node *LCA(node* root,node *p ,node *q){node* temp;while(p!=NULL){   p=p->parent;   temp = q;   while(temp!=NULL)   {      if(p==temp->parent)         return p;      temp = temp->parent;}}}6.某服务器流量统计器,每天有1000亿的访问记录数据,包括时间、url、ip。设计系统实现记录数据的保存、管理、查询。要求能实现一下功能:(1)计算在某一时间段(精确到分)时间内的,某url的所有访问量。(2)计算在某一时间段(精确到分)时间内的,某ip的所有访问量。答案参见下题。7.假设某个网站每天有超过10亿次的页面访问量,出于安全考虑,网站会记录访问客户端访问的ip地址和对应的时间,如果现在已经记录了1000亿条数据,想统计一个指定时间段内的区域ip地址访问量,那么这些数据应该按照何种方式来组织,才能尽快满足上面的统计需求呢,设计完方案后,并指出该方案的优缺点,比如在什么情况下,可能会非常慢?(参考答案:用B+树来组织,非叶子节点存储(某个时间点,页面访问量),叶子节点是访问的IP地址。这个方案的优点是查询某个时间段内的IP访问量很快,但是要统计某个IP的访问次数或是上次访问时间就不得不遍历整个树的叶子节点。或者可以建立二级索引,分别是时间和地点来建立索引。)8.腾讯最新面试题:服务器内存1G,有一个2G的文件,里面每行存着一个QQ号(5-10位数),怎么最快找出出现过最多次的QQ号。首先你要注意到,数据存在服务器,存储不了(内存存不了),要想办法统计每一个qq出现的次数。比如,因为内存是1g,首先 你用hash 的方法,把qq分配到10个(这个数字可以变动,比较)文件(在硬盘中)。相同的qq肯定在同一个文件中,然后对每一个文件,只要保证每一个文件少于1g的内存,统计每个qq的次数,可以使用hash_map(qq, qq_count)实现。然后,记录每个文件的最大访问次数的qq,最后,从10个文件中找出一个最大,即为所有的最大。9.腾讯2.如何求根号2的值,并且按照我的需要列出指定小数位,比如根号2是1.141 我要列出1位小数就是1.1 2位就是1.41, 1000位就是1.414...... 等。。#include <stdio.h>
double sqrtn(int n, int m){    long double ln = n*1.0;    long double left  = 0;    long double right = ln;    long double err = 1, mid;    for(int i=0;i<m;i++)    {        err *= 0.1;    }    while(true)    {        mid = (left + right) / 2;        if(mid*mid > ln)        {            right = mid;        }        else if(mid*mid < ln)        {            left = mid;        }        else        {int res = (int)(mid/err);            return res*err;        }        if(right - left < err)        {int res = (int)(mid/err);            return res*err;        }    }}
void main(){long double res = sqrtn(2,8);printf("%.10f\n",res);}10.给定一个字符串的集合,格式如:{aaa bbb ccc}, {bbb ddd},{eee fff},{ggg},{ddd hhh}要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,例如上例应输出{aaa bbb ccc ddd hhh},{eee fff}, {ggg}。查了查网上的解法,只看到一个(参见http://blog.csdn.net/lillllllll/article/details/4162605),有网上一位仁兄做了以下改进,说明如下:1. 首先得到所有元素的集合(aaa, bbb, ccc, ddd, eee, fff, ggg, hhh),复杂度O(N),N是所有元素的个数;2. 为所有集合标记一个二进制数,来表示包含哪些集合,得到数组int bina[5]复杂度O(N^2);如题,{aaa, bbb, ccc} = 1 1 1 0 0 0 0 0,{bbb, ddd} = 0 1 0 1 0 0 0 0,{eee, fff} = 0 0 0 0 1 1 0 0,{ggg} = 0 0 0 0 0 0 1 0,{ddd, hhh} = 0 0 0 1 0 0 0 1,3. 然后写一个函数,判断int数组中的第一个元素是否与其他元素&操作为空,复杂度为O(M),M是原集合的个数a. 为空则输出该元素对应的集合,并删除第一个元素,递归调用本方法;b. 不为空则与那个元素做或操作合并,删除那个元素,递归调用本方法;c. 如果只剩下一个元素则输出其对应的字符串;4. 所有的结合已经得到了。
11.创新工场面试题:abcde五人打渔,打完睡觉,a先醒来,扔掉1条鱼,把剩下的分成5分,拿一份走了;b再醒来,也扔掉1条,把剩下的分成5份,拿一份走了;然后cde都按上面的方法取鱼。问他们一共打了多少条鱼,写程序和算法实现。提示:共打了多少条鱼的结果有很多。但求最少打的鱼的结果是3121条鱼(应该找这5个人问问,用什么工具打了这么多条鱼)。本题和第一题一样;#include <iostream>  using namespace std;    int main()  {    int e, d, c, b, a;    for(int i = 0, f = 0; i < 1/* 改?为a1就¨ª是º?最Á?小?答äe案ã? */; ++i, ++f){      for(; true; ++f){        if(f % 4){ continue; }        e = f / 4 * 5 + 1;  //从最后一个人开始 如果刚好合适 至少要有      if(e % 4){ continue; }        d = e / 4 * 5 + 1;        if(d % 4){ continue; }        c = d / 4 * 5 + 1;        if(c % 4){ continue; }        b = c / 4 * 5 + 1;        if(b % 4){ continue; }        a = b / 4 * 5 + 1;        break;      }    }    cout << "a = " << a << '\n';    return 0;  }  12.我们有很多瓶无色的液体,其中有一瓶是毒药,其它都是蒸馏水,实验的小白鼠喝了以后会在5分钟后死亡,而喝到蒸馏水的小白鼠则一切正常。现在有5只小白鼠,请问一下,我们用这五只小白鼠,5分钟的时间,能够检测多少瓶液体的成分?解答;把五个老鼠看成5位二进制位:          5 4 3 2 1第一瓶    0 0 0 0 1第二瓶    0 0 0 1 0第三瓶    0 0 0 1 1….第31瓶   1 1 1 1 1相应位的老鼠死了就可以判断是第几瓶有毒;13.在一维坐标轴上有n个区间段,求重合区间最长的两个区间段http://blog.csdn.net/julianxiong/article/details/733832314.请使用代码计算1234567891011121314151617181920*2019181716151413121110987654321大数相乘问题:#include <iostream> #include <string.h>  using namespace std;   void multiply(const char *a,const char *b);   int main() {     //cout<<"hicjiajia"<<endl;          string num1,num2;     // 初始状态用string来存储大数     cout<<"现在,来两个大数吧! "<<endl;     cin>>num1>>num2;          const char *p1=num1.c_str();    // 将string转为 const char *     const char *p2=num2.c_str();    // 将string转为 const char *     multiply(p1,p2);          system("pause");     return 0; }   void multiply(const char *a,const char *b) {      int i,j,ca,cb,*s;      ca=strlen(a);      cb=strlen(b);      s=(int *)malloc(sizeof(int)*(ca+cb));   //分配存储空间      for (i=0;i<ca+cb;i++) s[i]=0;      // 每个元素赋初值0            for (i=0;i<ca;i++)          for (j=0;j<cb;j++)              s[i+j+1]+=(a[i]-'0')*(b[j]-'0');                    for (i=ca+cb-1;i>=0;i--)        // 这里实现进位操作          if (s[i]>=10)          {              s[i-1]+=s[i]/10;               s[i]%=10;          }            char *c=(char *)malloc((ca+cb)*sizeof(char));  //分配字符数组空间,因为它比int数组省!      i=0;while(s[i]==0) i++;   // 跳过头部0元素      for (j=0;i<ca+cb;i++,j++) c[j]=s[i]+'0';      c[j]='\0';      for (i=0;i<ca+cb;i++) cout<<c[i];      cout<<endl;       free(s); }15.1分2分5分的硬币,组成1角,共有多少种组合设1分个数为x,2分个数为y,5分的硬币个数为z,则1*x+2*y+5*z=10;5*z=10-x-2*y;即:z x对应可能的取值0 10 8 6 4 2 0(6个)1 5 3 1(3个)2 0(1个)总共个数为6+3+1=10.因此,按照规律,本题目组合总数为10以内的偶数+5以内的奇数+0以内的偶数某个偶数m以内的偶数个数(包括0)可以表示为m/2+1=(m+2)/2某个奇数m以内的奇数个数也可以表示为(m+2)/2
所以,求总的组合次数可以编程为:number=0;for (int m=0;m<=10;m+=5){number+=(m+2)/2;}cout<<number<<endl;这样程序是不是简单多了(只需要累加3次,而上面的3层循环呢?大家自己想想)。别人考你肯定不是考你会不会编这个程序,是考你如何去使程序的复杂度降低。6分、4分、2分组成100分怎么处理?2分为x,4分为y,6分为z。则6*z=100-2*x-4*y,可化简为:3*z=50-x-2*yz可能的取值为0、1、2•••16,当z=0时,x可以为50 48 46•••2 0(26个)当z=1时,x可以为47 45 43•••3 1(24个)当z=2时,x可以为44 42 40•••2 0(23个)当z=3时,x可以为41 39 37•••3 1(21个)当z=15时,x可以为5 3 1(3个)当z=16时,x可以为2 0(2个)
因此,按照规律,本题目组合总数为50以内的偶数+47以内的奇数+44以内的偶数+•••+5以内的奇数+2以内的偶数某个偶数m以内的偶数个数(包括0)可以表示为m/2+1=(m+2)/2某个奇数m以内的奇数个数也可以表示为(m+2)/2
所以,求总的组合次数可以编程为:number=0;for (int m=0;m<=50;m+=3){number+=(m+2)/2;}cout<<number<<endl;是不是可以看出规律了呢?实际上就是看表达式(这里是3*z=50-x-2*y),就是把最大乘数(这里是3)放在一边,这也是m增加的步长。而m的最大取值也就是表达式中的这个常数。16.解释下面ptr含义和不同double* ptr = &value;//ptr是一个指向double类型的指针,ptr的值可以改变,ptr所指向的value的值也可以改变 const double* ptr = &value//ptr是一个指向const double类型的指针,ptr的值可以改变,ptr所指向的value的值不可以改变double* const ptr=&value//ptr是一个指向double类型的指针,ptr的值不可以改变,ptr所指向的value的值可以改变const double* const ptr=&value//ptr是一个指向const double类型的指针,ptr的值不可以改变,ptr所指向的value的值也不可以改变2、去掉const属性,例: const double value = 0.0f; double* ptr = NULL;怎么才能让ptr指向value?强制类型转换,去掉const属性,如ptr = <const_cast double *>(&value);
17.如果用一个循环数组q[0..m-1]表示队列时,该队列只有一个队列头指针front,不设队列尾指针rear,求这个队列中从队列投到队列尾的元素个数(包含队列头、队列尾)(华赛面试题、腾讯笔试题)。貌似没有找到很好的解法,只能设置一个count计数;
18题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。例如输入“I am a student.”,则输出“student. a am I”。这种题是很无聊的,而且用istream什么就没有可以做的了,思路:倒着遍历字符串,查找到一个空格后,输出本空格与上次空格之间的内容。可以用\0临时替代printf#include <stdio.h>#include <stdlib.h>#include <string.h>
#define MAX 1024
void reverse_print(char* str){// Get lenint len = strlen(str);int i = len-1;int last = len;char tmp;// Find from last to firstwhile(i>=0){if( str[i]==' ' || i==0){tmp = str[last];str[last] = '\0';if(i==0 && str[i]!=' '){printf("%s ", str+i);}else{printf("%s ", str+i+1);}str[last] = tmp;last = i;}i--;}}
int main(){char* buf = NULL;int len = 0;len = getline(&buf, &len, stdin);if(len==-1){printf("getline error.\n");return -1;}else{buf[len] = '\0';buf[len-1] = '\0'; // \nreverse_print(buf);if(buf){free(buf);}}return 0;}


19.十月百度:一个数组保存了N个结构,每个结构保存了一个坐标,结构间的坐标都不相同,请问如何找到指定坐标的结构(除了遍历整个数组,是否有更好的办法)?(要么预先排序,二分查找。要么哈希。hash的话,坐标(x,y)你可以当做一个2位数,写一个哈希函数,把(x,y)直接转成“(x,y)”作为key,默认用string比较。或如Edward Lee所说,将坐标(x, y)作为 Hash 中的 key。例如(m, n),通过 (m,n) 和 (n, m) 两次查找看是否在 HashMap 中。也可以在保存时就规定 (x, y) , x < y ,在插入之前做个判断。)
20.(1的数目)给定义个十进制正整数N,写下从1开始,到N的所有整数,然后数一下其中出现的所有1的个数。例如N=12,我们会有1,10,11,12,   1的个数为5解答:假设N=abcde,这里a,b,c,d,e分别是十进制数N的各个数位上的数字。如果要计算百位上出现的1的次数,它将会受到三个因素的影响:百位上1的数字,百位以下(低位)的数字,百位(更高位)以上的数字。如果百位数为0,如12013,则百位出现1的情况有12*当前位数(100)如果百位数为1,如12113,则百位出现1的情况有12*100+114如果百位数不为1,如12213,则百位出现1的情况有(12+1)*100实现代码:#include<iostream>using namespace std;int sum1s(int n){int lowerNum = 0;int currNum = 0;int highNum = 0;int i = 1;int count = 0;while(n/i != 0){lowerNum = n-(n/i)*i;currNum = (n/i)%10;highNum  =n/(i*10);switch(currNum){case 0:count +=highNum*i;break;case 1:count +=highNum*i + (lowerNum+1);break;default:count +=(highNum+1)*i;break;}i*=10;}return count;}void main(){int num;while(cin>>num)cout<<sum1s(num)<<endl;}21相信大家都使用过百度搜索框的suggestion功能(如下图所示)。百度搜索框中的suggestion提示功能如何实现的?请给出实现思路和主要的数据结构、算法。有什么优化思路可以使得时间和空间效率最高?首先通过根据搜索日志,统计出热词出现的次数。同时还需加入一些常用词语。将热词和常用词语赋予一定的权重,做一棵trie数。根据用户输入的单词,去trie书中进行匹配,然后取其权重最高的前K个,取前k个,可以采用top k算法。22腾讯实习生笔试题:两个数组a[N],b[N],其中A[N]的各个元素值已知,现给b[i]赋值,b[i] = a[0]*a[1]*a[2]...*a[N-1]/a[i];要求:1.不准用除法运算2.除了循环计数值,a[N],b[N]外,不准再用其他任何变量(包括局部变量,全局变量等)3.满足时间复杂度O(n),空间复杂度O(1)。解答:先从右往左推出b[i]右边的乘积和存到b[i]中,再从左往右推出b[i]左边的乘积和存到b[0]中,用b[i]*b[0]就是最后的结构,最后在计算b[0]就得出最后结果:#include <stdio.h>#define MAX 100int main (){    int n =0 ;    int a[MAX];    int b[MAX];    int i;    scanf("%d",&n);    for(i=0;i<n;i++)        scanf("%d",a+i);    b[n-1]=1;    b[0]=1;    //计算右边成绩和    for(i=n-2;i>0;i--)        b[i]=a[i+1]*b[i+1];    for(i=1;i<n;i++)    {        //保存左边乘积和        b[0]=b[0]*a[i-1];        //将本行两部分的值乘倒一起,得到最后结果        b[i]=b[i]*b[0];    }    b[0]=1;    for(i=1;i<n;i++)        b[0]=b[0]*a[i];    for(i=0;i<n;i++)        printf("%-9d",b[i]);    printf("\n");    return 0 ;}23十月百度:一个数组保存了N个结构,每个结构保存了一个坐标,结构间的坐标都不相同,请问如何找到指定坐标的结构(除了遍历整个数组,是否有更好的办法)?解答:用hash_map实现,因为hash_map是用hash_table实现的,所有查询复杂度为O(1)24百度最新面试题:现在有1千万个随机数,随机数的范围在1到1亿之间。现在要求写出一种算法,将1到1亿之间没有在随机数中的数求出来。(编程珠玑上有此类似的一题,如果有足够的内存的话可以用位图法,即开一个1亿位的bitset,内存为100m/8== 12.5m, 然后如果一个数有出现,对应的bitset上标记为1,最后统计bitset上为0的即可。)25.设计包含min函数的栈。定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。要求函数min、push以及pop的时间复杂度都是O(1)。#include <iostream>
using namespace std;
struct node{int data;int min;};
struct MinStack{node *data;int top;int size;};

MinStack initStack(int size){MinStack stack;stack.data = new node[size];stack.size = size;stack.top = 0;return stack;}
void freeStack(MinStack stack){delete[] stack.data;}int minStack(MinStack stack){if(0 == stack.top)return INT_MAX;return stack.data[stack.top-1].min;}void push(MinStack &stack, int data){if(stack.size == stack.top)return ;stack.data[stack.top].data = data;int tem = minStack(stack);stack.data[stack.top].min = min(data,tem);stack.top++;}
int pop(MinStack &stack){if(0 == stack.top)return 0;return stack.data[--stack.top].data;}
void main(){MinStack stack = initStack(5);push(stack,5);push(stack,4);push(stack,2);push(stack,3);int res = minStack(stack);cout<<res<<endl;freeStack(stack);}