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

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/7338323
14.请使用代码计算
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*y
z可能的取值为0、一、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的值也不能够改变
二、去掉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 len
int len = strlen(str);
int i = len-1;
int last = len;
char tmp;
// Find from last to first
while(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'; // \n
reverse_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 100
int 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);
}