迅雷近几年笔试题及其分析

作者:寒小阳
时间:2013年9月。
出处:http://blog.csdn.net/han_xiaoyang/article/details/11533437
声明:版权所有,转载请注明出处,谢谢。


前言:

    今年迅雷依旧是动作很快的公司之一,才9月初就已经笔试完了,看来还是想赶在互联网公司招聘大潮前抢些人。虽然传闻迅雷工作挺累的,然后待遇一般(不确定数据可靠度有多高,不过都说根据水平不同,研发base高的差不多腾讯的水平,低的不过万),但是宣讲会和笔试的时间早,肯定和去年一样还是人山人海,也不乏大牛们过去练练手。不过maybe明年会上市吧,恩,这个对很多人还是有吸引力的。好吧,胡说八道闲扯一大堆,进入正题吧。把这几年(包括今年)的迅雷笔试题拿来揉了揉,放在一起,我们看看他家都考察些什么,这类公司需要做些什么准备吧。

    先上题吧,我会对每道题稍加解释一下(当然,本人水平很菜,若有不当之处,请大家指出);题目和答案过后,本文最后我会对考点总结汇总一下。


两年前的笔试题:

一、选择题

1.下列程序的输出结果为:(B)  
#include<iostream.h>
void main()
{
       char* a[ ] = { "hello", "the", "world"};

       char** pa = a;

       pa++;

       cout<<”*pa<<endl;

}

A) theworld    B) the   C) ello    D) ellotheworld

分析:a是指针的数组
char** p = a; //char** p = &a[0]
p++;//p是指针自增+4,而a中元素是指针,每个正好四个字节,因此p++后恰好p= &a[1]
*p=a[1];输出"the",输出结果为B


2. 已知二叉树后序遍历序列是bfegcda,中序遍历序列是badefcg,它的前序遍历序列是:(B)

A) abcdefg     B) abdcefg    C) adbcfeg    D) abecdfg

分析:很有代表性的一道题目,去年参加微软笔试的时候也有类似的题目。后序遍历中的最后一个元素是根节点,a,然后查找中序中a的位置,把中序遍历分成 b a defcg,易知左子树为b,右子树为defcg,再递归求解,可画出原始二叉树,故知前序遍历序列为B。

 

3. 栈和队列的共同特点是:(C)

A) 都是先进先出                       B) 都是先进后出

C) 只允许在端点处插入和删除元素       D) 没有共同点

分析:基础题,不解释-_-||

 

4. 下面程序的运行结果为:(A)

#include <iostream.h>

void main()

{

       int a, x;

       for(a = 0, x = 0; a<=1 && !x++; a++)

       {

              a++;

       }

       cout<< a << x <<endl;

}

A) 21             B) 22             C) 32             D) 41


 

5. 下列选项,不正确的是:(B) 

A) for(int a=1; a<=10; a++);

B) int a=1;

   do

   {

       a++;

    }while(a<=10)

C) int a=1;

   while(a<=10)

   {

          a++;

}

D) for(int a= 1; a<=10; a++)a++;

分析:个人认为意义不大的一道题,考察程序语句是否书写正确,B选项的while后没有分号。


6. 下面关于数组的初始化正确的是:(B)

A) char str[2] = {“a”,”b”};

B) char str[2][3]={“a”,”b”};

C) char str[2][3]={{‘a’,’b’},{‘e’,’d’},{‘e’,’f’}};

D) char str[] = {“a”, “b”};

分析:A中字符变量不能存放字符串,C中维度错了,D和A的问题一样

 

7. 下列说法正确的是:(B)

A) 内联函数在运行时是将该函数的目标代码插入每个调用该函数的地方

B) 内联函数在编译时是将该函数的目标代码插入每个调用该函数的地方

C) 类的内联函数必须在类体内定义

D) 类的内联函数必须在类体外通过关键字inline定义

 

8.下面对静态成员的描述中,正确的是:(D)

A) 静态数据成员可以在类体内初始化

B) 静态数据成员不可以被类的对象调用

C) 静态数据成员不能受private控制符的作用

D) 静态数据成员可以直接用类名调用

 

9. 下列运算符中,在C++语言中不能重载的是:(C)

A) *                B) >=             C) ::              D) delete

分析:详见找工作笔试面试那些事儿(4)---C++函数高级特征

 

10 下面关于多态性的描述,错误的是:(C)

A) C++语言的多态性分为编译时的多态性和运行时的多态性

B) 编译时的多态性可通过函数重载实现

C) 运行时的多态性可通过模板和虚函数实现

D) 实现运行时多态性的机制称为动态绑定

分析:模板的是编译时多态性,而虚函数是运行时。

 

11. 如果进栈序列为e1,e2,e3,e4,e5,则可能的出栈序列是:(D)

A) e3,e2,e5,e4,e1

B) e2,e3,e5,e4,e1

C) e3,e2,e4,e5,e1

D) 以上都有可能

分析:经常考的一道题,去年微软笔试也考了类似的题目。A为e1入,e2入,e3入,e3出,e2出,e4入,e5入,e5出,e4出,e1出;B为e1入,e2入,e2出,e3入,e3出,e4入,e5入,e5出,e4出,e1出;C为e1入,e2入,e3入,e3出,e2出,e4入,e4出,e5入,e5出,e1出。

 

12 下面关于类和对象的描述中,错误的是:(A)

A) 类就是C语言中的结构体类型,对象就是C语言中的结构体变量

B) 类和对象之间的关系是抽象和具体的关系

C) 对象是类的实例,一个对象必须属于一个已知的类

D) 类是具有共同行为的若干对象的统一描述体

 

13.下面关于数组的描述错误的是:(CD)?

A) 在C++语言中数组的名字就是指向该数组第一个元素的指针

B) 长度为n的数组,下标的范围是0-n-1

C) 数组的大小必须在编译是确定

D) 数组只能通过值参数和引用参数两种方式传递给函数

说明:感谢@Emiyasstar__童鞋的指正,关于C选项,C99中提到了variable length arrays的概念,允许在编译时不指定数组大小,而在运行时才确定,详见http://www.cppblog.com/Walker/articles/80805.html。所以严格来说,本题C和D都是错的。

 

14. 引用标准库时,下面的说法你认为哪个是正确的:(B)

A) 语句#include “stdlib.h”是正确的,但会影响程序的执行速度

B) 语句#include <stdlib.h>是正确的,而且程序执行速度比#include “stdlib.h”要快

C) 语句#include <stdlib.h>和#include “stdlib.h”都是正确的,程序执行速度没有区别

D) 语句#include “stdlib.h”是错误的

分析:include ""是先从本地目录开始寻找,然后去寻找系统路径,而Include<> 相反先从系统目录,后从本地目录。

 

15.设a、b、c、d、m、n均为int型变量,且a=5、b=6、c=7、d=8、m=2、n=2,则逻辑表达式(m=a>b)&&(n=c>d)运算后,n的值为:(C)

A) 0               B) 1               C) 2               D) 7

分析:m=a>b后m=0,表达式为假,&&后半部分不会操作,因此n为初始值2


16.不能作为重载函数的调用的依据是:(C)

A) 参数个数                              B) 参数类型

C) 函数类型                              D) 函数名称

 

17.下列程序的输出结果为: (D)

#include< iostream. h>
int func(int n)
{
  if〔n<1)return 1;

    else return n+func(n-1);

    return 0;
}
void main()
{

cout<<func(5)<<endl;

}

A) 0        B)10             C)15            D)16

 

18.建立派生类对象时,3种构造函数分别是a(基类的构造函数)、b(成员对象的构造函数)、c(派生类的构造函数)这3种构造函数的调用顺序为: (A)

A)abc                                                                B)acb

C)cab                                                                  D)cba

 

19. 如果友元函数重载一个运算符时,其参数表中没有任何参数则说明该运算符是:(D)

A)一元运算符                                                      B)二元运算符

C)选项A)和选项B)都可能                               D)重载错误

分析:C++中用友元函数重载运算符至少有一个参数,重载一目运算符要有一个参数,重载二目运算符要有两个参数。

 

20. 有以下程序段:(D)

#define F(X,Y)   (X)-- (Y)++ (X)*(Y);

int i, a = 3, b = 4;

for( i = 0; i<5; i++)   F(a,b)

printf(“%d, %d”, a, b);

输出结果是:()

A) 3, 4                                       B) 3, 5

C) -2, 5                                      D) -2, 9

 

21. 下列for循环的循环体执行次数为:(C)

for(int i(10), j(1); i=j=0; i++, j--)

A) 0;       B) 1;       C) 无限;        D)以上都不对

分析:赋值语句判断为真,一直执行

 

22. 下面程序的输出结果是(D)

char *p1= “123”, *p2 = “ABC”, str[50]= "xyz";

strcpy(str+2,strcat(p1,p2));

cout << str;

A)xyz123ABC                                                       B)z123ABC

C)xy123ABC                                                        D)出错

分析:p1和p2指向的是常量存储区的字符串常量,没法连接,会有问题

 

23.下面函数的执行结果是输出(B)

char str[ ] = “xunlei”;

char *p = str;

int n = 10;

printf(“%d, %d, %d/n”, sizeof(str), sizeof(p), sizeof(n));

A) 4, 4, 4                                                 B) 7, 4, 4

C) 6, 4, 4                                                 D) 6, 6, 4

分析:sizeof的问题,详见找工作笔试面试那些事儿(3)---内存管理那些事

 

33. 有下列程序段:

char *p, *q;

p = (char*) malloc(sizeof(char) * 20);

q = p;

scanf(“%s %s”, p, q);

printf(“%s %s/n”, p, q);

若从键盘输入:abc def, 则输出结果是(A)

A) def def                     B) abc def

C) abc d                       D) d d

分析:q=p;因此p,q指向的是同一段内存.scanf先是把abc写到p指向的空间,再把def写到q指向的空间,也就是同一段空间,因此abc被def覆盖了。

 

34.现在有以下语句:

struct _THUNDER{

       int iVersion;

       char cTag;

       char cAdv;

       int iUser;

       char cEnd;

}Thunder;

int sz = sizeof(Thunder);

则执行后,变量sz的值将得到(D)

A) 11             B) 12             C) 13             D) 16

分析:内存对齐问题,相关知识可参考http://blog.chinaunix.net/uid-10995602-id-2918694.html

 

35. 有如下程序段:

void GetMemeory(char* p)

              p = (char*) malloc (100);

void test()

{

char *str=NULL;

GetMemory(str);

strcpy(str,”Thunder”);

strcat(str+2, “Downloader”);

 printf(str);

}

请问运行Test函数结果是:(D)

A) Thunder Downloader                                 B) under Downloader

C) Thunderownloader                                    D) 程序崩溃

分析:在函数中给指针分配空间,实际上是给指针的临时变量分配空间,函数结束后,这个临时变量也消亡,而str仍然为NULL,没有为其分配空间,此时strcpy()是肯定会出错的。可参考找工作笔试面试那些事儿(3)---内存管理那些事

 

36. 函数调用exec((v1,v2), (v3,v4,v5),v6,v7);中,实参的个数是(A)

A) 4               B) 5               C) 6               D) 7             

 

37. p是指向类X的成员m的指针,s是类X的一个对象。现要给m赋值,(C)是正确的。

A) s.p = 5                                                        B) s->p = 5

C) s.*p = 5                                                       D) *s.p = 5

 

38. 函数fun(char* p) { return p;}的返回值是(B)

A)无确切值                                              B) 行参p中存放的地址值

C) 一个临时存储单元的地址                               D) 行参p自身的地址值

分析:可参考找工作笔试面试那些事儿(3)---内存管理那些事,返回的是形参p中存放的地址值。

 

39.a,b均为不等于0的整形变量,以下关系式恒成立的是:(C)

A) a*b/a*b == 1                                 B) a/b*b/a == 1

C) a/b*b + a%b == a                             D) a/b*b == a


40. 设有如下说明:

       typedef struct ST{ long a; int b; char c[2]; } NEW;

则下面叙述中正确的是:(C)

A)以上的说明形式非法                            B)ST是一个结构体类型 
C)NEW是一个结构体类型                           D)NEW是一个结构体变量

 

41. 下列表达式正确的是:(C)

A) 9++                  B) (x+y)++              C) c+++c+++c++                D) ++(a-b--)

 

42.在int b[ ][3] = {{1},{3,2},{4,5,6},{0}};中,sizeof(b) = (D)

A) 4                      B) 12                    C) 28                    D) 48

 

43.以下程序的输出结果是:(D)

#define M(x,y,z) x*y+z

main()

{

       int a=1, b=2, c=3;

       printf(“%d/n”,M(a+b,b+c,c+a));

}

A)19                   B) 17                    C) 15                    D) 12

分析:#define的边际效应,直接展开,变成a+b*b+c+c+a,详见找工作笔试面试那些事儿(1)---C,C++基础和编程风格(2)

 

44.若有以下定义和语句:

int u=010, v= 0x10, w=10;

printf(“%d,%d,%d/n”,u,v,w);

则输出结果是:(A)

A)8,16,10     B)10,10,10      C)8,8,10      D)8,10,10

分析:各种进制之间的转换,简单题,0x表示十六进制,0表示八进制。

 

45. 下面程序段的输出结果是:(B)

int a=5, b=4, c=3, d=2;

if(a>b>c)

       printf(“%d/n”,d);

else if((c-1>=d)==1)

       printf(“%d/n”, d+1);

else

       printf(“%d/n”, d+1);

A) 2                      B) 3                      C) 4                   D) 编译错误

 

46.有如下程序段,请问k的值是:(D)

enum {a, b=5, c, d=4, e} k; k =c;

A) 3                      B)4                     C) 5                      D) 6

 

47.有如下程序段:

int i, n = 0;

double x = 1, y1 = 2.1/1.9, y2 = 1.9/2.1;

for( i = 1; i<22; i++)

       x = x*y1;

while( x!=1.0)

{

       x =x*y2;

       n++;

}

printf(“%d/n”, n);

请问执行结果是:(C)

A) 21                    B) 22                    C)无限循环                  D) 程序崩溃

分析:浮点数的比较不可以用 = = 或者 != ,详见找工作笔试面试那些事儿(1)---C,C++基础和编程风格(2) ,会一直循环下去,选择C


48. 用树形结构表示实体之间联系的模型是(C)

A) 关系模型                       B) 网状模型                C) 层次模型                D)以上三个都是

 

49.有如下程序段:

char fun(char *);

main()

{

       char *s = “one”, a[5] = {0}, (*f1)(char *) = fun, ch;

}

则对函数fun的调用语句正确的是(C)

A) *f1(&a);                  B) f1(*s);                 C) f1(&ch)                   D) ch = *f1(s);要改成(*f1)(s)才正确

 

50.有如下程序段:

int c = 23;

printf(“%d/n”, c&c);

请问执行结果是:(C)

A) 0               B) 46             C) 23                    D) 以上都不对


二、填空题

1、下面的程序可以从1....n中随机输出m个不重复的数。请填空

knuth(int n, int m) 

{

    srand((unsigned int)time(0));

    for (int i=0; i<n; i++)

        if (    rand()%(n-i)<m  )

        {

           cout<<i<<endl;

                        m--            ;

        }

}

分析:1)由题意m必定小于n,从0至n-1中找出m个随机数,那么这n个数可以分为两组:要求的不重复的随机数(m个)+非要求的随机数(n-m个);i不断自增,n-i不断自减,所以 rand()%(n-i)最终会为0,而每得出一个要求的不重复的随机数,m自减,所以m最终也为零,所以当一共得带来m个要求数,循环会停止;if判断i是否为随机数的依据是rand()%(n-i)和m相比,可能是大于,也可能是小于,结果是随机的,而每个数符合条件的概率是m/n。 

         2)不过这里要提一下,这道题的这种答案本身也是有争议的,这种方法看似利用序号不重复原理实现随机数的不重复,但是当n=m时,将产生顺序数而不是随机数!看似巧妙却不符合要求,而且在n>>m时,其最先出现的值几乎铁定是0,1尤其是n=2m时,更是如此。

         3)水平有限,暂时想不出比较合理的答案,大家有好方法欢迎留言指教,非常感谢


2、 prim函数的功能是分解质因数。请填空

void prim(int m, int n)

{

    if (m>n)

    {

        while (   m%n   ) n++;

              m/=n            ;

       prim(m,n);

       cout<<n<<endl;

    }

}

分析:不整除就逐一增加除数,整除的话输出除数,然后再递归求解商的质因数。


3、下面程序的功能是输出数组的全排列。请填空

void perm(int list[], int k, int m)

{

    if (    k==m    )

    {

        copy(list,list+m,ostream_iterator<int>(cout," "));

        cout<<endl;

        return;

    }

    for (int i=k; i<=m; i++)

    {

        swap(&list[k],&list[i]);

              perm(list,k+1,m)       ;

        swap(&list[k],&list[i]);

    }

}

分析:这也是一道利用递归完成的题目了(递归真的是在各种笔试面试题里屡试不爽啊!),100题和《剑指offer》里面的典型题,全排列可以看做第一个位置上的数把整个数组里的数取一遍(这里用交换实现的),然后固定第一个位置,后m-1个数的全排列情况数。


三、解答题

1、用户启动迅雷时,服务器会以uid,login_time,logout_time的形式记录用户的在线时间;用户在使用迅雷下载时,服务器会以taskid,start_time,finish_time的形式记录任务的开始时间和结束时间。有效下载时间是指用户在开始时间和结束时间之间的在线时间,由于用户可能在下载的时候退出迅雷,因此有效下载时间并非finish_timestart_time之差。假设登录记录保存在login.txt中,每一行代表用户的上下线记录;下载记录保存在task.txt中,每一行代表一个任务记录,记录的字段之间以空格分开。计算每个用户的有效下载时间和总在线时间的比例。

分析:尴尬的是,博主自己对这道题,也写不出个确定的答案,所以这里贴一贴当时大家讨论的结果,大家有好的思路想法欢迎留言指正。

@qq120848369   没看懂,应该就是Map做个< Uid,vector< pair<int,int> > >的映射

@yby4769250 我也是想到map,转换成数学问题的话,就是线段问题了,但是,要对用户的所有task做一些逻辑时序合并,处理才能形成一个个线段,假如task1为[1,5],task2为[4,7],这个时候,在时序上,task1和task2有重叠,需要处理重叠位置,做合并,有效时序其实为task[1,7],处理重叠问题倒是有几个方法,可以直接转换为线段重叠,然后,算每段实线的和,就是全部的有效下载时间,这个貌似用可以用线段树来做

@yby4769250   题意就是要求所有有效下载时间之和,当时时间紧迫没想那么多,现在想想,其实,用一个栈就能非常容易的完成,非常类似于括号匹配的做法。这里仍然考虑到时序重合覆盖(就像括号嵌套)的问题。
例如下面的栈:
             t0_s|t0_f|t1_s|t2_s|t3_s|t3_f|t2_f|t1_f|t4_s|t5_s|t4_f|t5_f
                    |      ((()))               ||    ( { ) }      |
                           这里像括号嵌套              这里像括号交叉


//t0_s表示task0的开始时间,t0_f表示task0的结束时间

栈元素
struct Node
{
    char flag;       //标记tv是开始时间还是结束时间
    unsigned int tv; //时间值
};


把每一个task的按照start_time和finish_time的顺序压栈,并标记flag的值,形成上述栈,从栈顶开始弹栈,每一个f必然需要一个s匹配,如果一个f的下一个元素仍然是f,则这里出现嵌套,则把f压栈,直到遇到s,弹出f,计算最后一个f和s的值作为有效值(就像只需要最外层括号)。当出现上述栈中括号交叉时,其实根本不需要特殊处理,仍然当做嵌套处理,只不过是,这个时候把{)这两个匹配的括号,即把task的起止时间变换掉,方便处理。


2、在8X8的棋盘上分布着n个骑士,他们想约在某一个格中聚会。骑士每天可以像国际象棋中的马那样移动一次,可以从中间像8个方向移动(当然不能走出棋盘),请计算n个骑士的最早聚会地点和要走多少天。要求尽早聚会,且n个人走的总步数最少,先到聚会地点的骑士可以不再移动等待其他的骑士。

        从键盘输入n0<n<=64),然后一次输入n个骑士的初始位置xi,yi0<=xi,yi<=7)。屏幕输出以空格分隔的三个数,分别为聚会点(xy)以及走的天数.

分析:同上题,丢些讨论在下面吧,大家有什么好的解法,非常欢迎留言指教,谢谢大家了!

@failuer 贪心法不可以吗?每个骑士都最短时间到聚会地点,这样总天数应该就是最少的了。没下过象棋,是不是同一个地方不能同时有两个骑士?这样的话就需要考虑避免位置冲突的情况了。

@qq120848369 很明显就是双向广搜的扩展问题么,现在只不过是K个骑士同步做广搜,核心算法如下:
1)每一轮循环中,每个骑士做一步扩展的广搜,每个骑士有自己的标记(表示自己是否走过某个格子),每个骑士有自己的广搜队列.  所有骑士共享的是一张地图以及每个地图当前有几个骑士走过. 
2)随着每一轮循环,如果在做某个骑士的一步广搜的时候,会给每个这一步到达的格子的全局共享地图的计数+1,立即判断这些格子的计数是否为K,如果是,那么说明找到了,就是这个格子可以让所有的骑士走最少的步到达

@Kevin_qing 1).求n个点坐标平均值。 记为点c.        2).计算c到各点距离和d0 ,计算点c周围8个点到各点距离d。 如果某个点d<d0,则继续往该方向搜索。     3).搜索到某个点d0<周围8个点时得知结果

@tianhaoma8888  

1)棋盘上面一个骑士的位置为(x,y),到棋盘上面一个位置(x0,y0)。需要走多少步的计算公式是:MAX(ABSOLUTE(x-x0), ABSOLUTE(y-y0)); ABSOLUTE是取绝对值,MAX是求最大值。

2)棋盘上面,假设我们有两个骑士,骑士A位置(xa,ya),骑士B位置(xb,yb);根据1我们能知道从一个骑士走到另外一个骑士需要走多少步,然后这个步数除以2 就能得到他们走多少步就能相聚(分别走),相聚地点的计算,也就是这两个骑士的中间点。当然这个中间点可能是有多个的。
例如 xa=0,ya=0, xb=7,yb=7.能得到的可能的相聚地点 就是(3,3),(3,4),(4,3),(4,4).然后把去计算所有骑士走道这些可能的相聚地点所需要的时间,那个相聚点,骑士所需要走的总天数最小。。。。。

[cpp]  view plain copy
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. #define MAX(a, b) ( (a) > (b) ? (a) : (b) )  
  5. #define ABSOLUTE(a) ( (a) > 0 ? a : -(a) )  
  6.   
  7. struct KnightPt  
  8. {  
  9.     int x;  
  10.     int y;  
  11. };  
  12.   
  13. int knightNumber = 0;//骑士个数  
  14. int minGatherDays = 0;//相聚天数  
  15. int minWalkDay = 0;  
  16. int possibleGatherPtNumber = 0;//相聚地点可能是多个点(1~4),可能相聚地点的个数  
  17. int gatherDays[4] = {0};  
  18. int walkDays[4] = {0};//每个可能相聚地点的相聚天数  
  19. KnightPt kinghtPt[64] = {0};//所有骑士的位置  
  20. KnightPt possibleGatherPt[4] = {0};//可能相聚地点的集合  
  21. //获取骑士可能相聚的地点的集合  
  22. void getPossibleGatherPoint()  
  23. {  
  24.     int minXPt = 8, minYPt = 8, maxXPt = 0, maxYPt = 0;  
  25.     //根据所有骑士的位置,骑士位置X方向最小值和最大值,Y方向最小值和最大值  
  26.     for(int i = 0; i < knightNumber; i++)  
  27.     {  
  28.         if(kinghtPt[i].x < minXPt) minXPt = kinghtPt[i].x;  
  29.         if(kinghtPt[i].y < minYPt) minYPt = kinghtPt[i].y;  
  30.         if(kinghtPt[i].x > maxXPt) maxXPt = kinghtPt[i].x;  
  31.         if(kinghtPt[i].y > maxYPt) maxYPt = kinghtPt[i].y;  
  32.     }  
  33.     //计算X方向最小值和X方向最大值的中间点,使用float数据类型是因为可能中间点处于棋盘线上。  
  34.     //例如X方向最小值为0,X方向最大值为7,中间值就是3.5,位于棋盘线上。同样Y方向同样处理  
  35.     float midXPt = minXPt + (float)(maxXPt - minXPt) / 2;  
  36.     float midYPt = minYPt + (float)(maxYPt - minYPt) / 2;  
  37.     int midXPt0 = (int)midXPt;  
  38.     int midXPt1 = (int)(midXPt + 0.5);  
  39.     int midYPt0 = (int)midYPt;  
  40.     int midYPt1 = (int)(midYPt + 0.5);  
  41.     //根据得到的中间点,计算出可能的位置(最多4个),他们都有可能是相聚点。  
  42.     possibleGatherPt[possibleGatherPtNumber].x = midXPt0;  
  43.     possibleGatherPt[possibleGatherPtNumber].y = midYPt0;  
  44.     possibleGatherPtNumber++;  
  45.     if(midXPt0 != midXPt1)  
  46.     {  
  47.         possibleGatherPt[possibleGatherPtNumber].x = midXPt1;  
  48.         possibleGatherPt[possibleGatherPtNumber].y = midYPt0;  
  49.         possibleGatherPtNumber++;  
  50.     }  
  51.     if(midYPt0 != midYPt1)  
  52.     {  
  53.         possibleGatherPt[possibleGatherPtNumber].x = midXPt0;  
  54.         possibleGatherPt[possibleGatherPtNumber].y = midYPt1;  
  55.         possibleGatherPtNumber++;  
  56.     }  
  57.     if(midXPt0 != midXPt1 && midYPt0 != midYPt1)  
  58.     {  
  59.         possibleGatherPt[possibleGatherPtNumber].x = midXPt1;  
  60.         possibleGatherPt[possibleGatherPtNumber].y = midYPt1;  
  61.         possibleGatherPtNumber++;  
  62.     }  
  63. }  
  64. //获取所有骑士相聚需要走的天数  
  65. void getWalkDays()  
  66. {  
  67.     for(int i = 0; i < possibleGatherPtNumber; i++)  
  68.     {  
  69.         KnightPt kpt = possibleGatherPt[i];  
  70.         for(int j = 0; j < knightNumber; j++)  
  71.         {  
  72.                      //得到一个骑士要走多少天  
  73.             int oneKnightWalkDay = MAX(ABSOLUTE(kinghtPt[j].x - kpt.x), ABSOLUTE(kinghtPt[j].y - kpt.y));  
  74.                      //骑士行走的最多天数,为相聚的天数  
  75.             gatherDays[i] = MAX(gatherDays[i], oneKnightWalkDay);  
  76.                      //获取所有骑士相聚的天数  
  77.             walkDays[i] += oneKnightWalkDay;  
  78.         }  
  79.     }  
  80.       
  81.     minGatherDays = gatherDays[0];  
  82.     minWalkDay = walkDays[0];  
  83.     for(int j = 0; j < possibleGatherPtNumber; j++)  
  84.     {  
  85.         if(gatherDays[j] < minGatherDays) minGatherDays = gatherDays[j];  
  86.         if(walkDays[j] < minWalkDay) minWalkDay = walkDays[j];  
  87.     }  
  88. }  
  89.   
  90. int wmain(wchar_t *argv[], int argn)  
  91. {  
  92.     cout << "input knight number. range(0 < n <= 64)" << endl;  
  93.     cin >> knightNumber;  
  94.     cout << "knight all position" << endl;  
  95.     for(int i = 0; i < knightNumber; i++)  
  96.     {  
  97.         cout << "input knight " << i+1 << " position range( 0 ~ 7)" << endl;  
  98.         cin >> kinghtPt[i].x;  
  99.         cin >> kinghtPt[i].y;  
  100.     }  
  101.     getPossibleGatherPoint();  
  102.     getWalkDays();  
  103.   
  104.     for(int k = 0; k < possibleGatherPtNumber; k++)  
  105.     {  
  106.         if(minGatherDays == gatherDays[k] && minWalkDay == walkDays[k])  
  107.         {  
  108.             cout << "--------------------------" << endl;  
  109.             cout << minGatherDays << " days, all gather can gather" << endl;  
  110.             cout << "gather position is x = " << possibleGatherPt[k].x << " y = " << possibleGatherPt[k].y << endl;  
  111.             cout << "all knight walk day is " << minWalkDay << endl;  
  112.             cout << "--------------------------" << endl;  
  113.         }  
  114.     }  
  115.   
  116.     system("pause");  
  117. }  


一年前的试题:

第一题------(30分)

请实现以下函数把一个用阿拉伯字符串表示的自然数(串长大于0,小于13,串保证是合法的)转换成相应的中文字符串。例如1234567890,应输出“十二亿三千四百五十六万七千八百九十” 。               
分析:这是一道很经典的题目。犹记得去年博主面有道实习的时候也被问到了这道题目。首先呢,这题用java处理起来还是会比C++在代码上会简洁一些。先看个java版本的吧,话说博主代码能力很水,有问题欢迎大家留言指正,但求轻喷,谢谢。

[java]  view plain copy
  1. package com.test;  
  2.   
  3. public class NumberProcess  {  
  4.   
  5.     private static final String[] UNITS = { """十""百""千""万""十""百""千""亿""十""百""千", };  
  6.     private static final String[] NUMS = { "零""一""二""三""四""五""六""七""八""九", };  
  7.   
  8.     /**  
  9.      *  阿拉伯数字转换成中文字符串  
  10.      *  @param value 要转换的数字  
  11.      *  @return 返回数字转后的中文字符串  
  12.      */  
  13.     public static String number2Chinese(int value) {  
  14.   
  15.         String result = ""//转译结果   
  16.   
  17.         for (int i = String.valueOf(value).length() - 1; i >= 0; i--) {  
[java]  view plain copy
  1.             int r = (int) (value / Math.pow(10, i));//value / Math.pow(10, i) 截位匹配单位   
  2.             result += NUMS[r % 10] + UNITS[i];  
  3.         }  
  4.   
  5.         result = result.replaceAll("零[十, 百, 千]""零");//匹配字符串中的 "零[十, 百, 千]" 替换为 "零"  
  6.         result = result.replaceAll("零+""零");//匹配字符串中的1或多个 "零" 替换为 "零"  
  7.         result = result.replaceAll("零([万, 亿])""$1");  
  8.         result = result.replaceAll("亿万""亿"); //亿万位拼接时发生的特殊情况  
  9.   
  10.         if (result.startsWith("一十")) { //判断是否以 "一十" 开头 如果是截取第一个字符  
  11.             result = result.substring(1);  
  12.         }  
  13.   
  14.         if (result.endsWith("零")) { //判断是否以 "零" 结尾 如果是截取除 "零" 外的字符  
  15.             result = result.substring(0, result.length() - 1);  
  16.         }  
  17.   
  18.         return result;  
  19.     }  
  20.   
  21.     public static void main(String[] args) {  
  22.         System.out.println(NumberProcess .number2Chinese(1234567890));  
  23.     }  
  24. }  
C++版的一直有些问题,可参照 http://lovinchan.iteye.com/blog/266628 中编写,等博主整理好了再上来更新。

第二题------(30分)

求一个全英文字符串的不同组合数目,串的长度小于30。
实例1“cat”有7种不同的组合:c、a、t、ca、ct、at、cat   示例2 “all”有5种不同的组合:a、l、al、ll、all
分析:就像之前找工作笔试面试那些事儿(15)---互联网公司面试的零零种种和多家经验中提到的,在做算法题的时候,递归和分治是时常要存于脑中的思路。这题如果考虑
递归求解的话,考虑求长度为n的字符串中m个字符的组合,设为C(n,m)。原问题的解即为所有的C(n, 1), C(n, 2),...C(n, n)。对于求C(n, m),从第一个字符开始扫描,每个字符有两种情况,要么被选中,要么不被选中,如果被选中,递归求解C(n-1, m-1)。如果未被选中,递归求解C(n-1, m)。不管哪种方式,n的值都会减少,在n=0或m=0时递归结束。这题有个小问题是这里的“不同”,博主的方法能输出所有结果,但是是不是会有重复(求教)?

[cpp]  view plain copy
  1. //函数功能 : 在字符串中选m个字符  
  2. //函数参数 : pStr为字符串,m为选的元素个数,result为选中的字符  
  3. //返回值 :   无  
  4. void Combination_m(char *pStr, int m, vector<char> &result)  
  5. {  
  6.     if(pStr == NULL || (*pStr == '\0'&& m != 0))  
  7.         return;  
  8.     if(m == 0) //递归终止条件  
  9.     {  
  10.         for(unsigned i = 0; i < result.size(); i++)  
  11.             cout<<result[i];  
  12.         cout<<endl;  
  13.         return;  
  14.     }  
  15.     //选择这个元素  
  16.     result.push_back(*pStr);  
  17.     Combination_m(pStr + 1, m - 1, result);  
  18.     result.pop_back();  
  19.     //不选择这个元素  
  20.     Combination_m(pStr + 1, m, result);  
  21. }  
  22. //函数功能 : 求一个字符串的组合  
  23. //函数参数 : pStr为字符串  
  24. //返回值 :   无  
  25. void Combination(char *pStr)  
  26. {  
  27.     if(pStr == NULL || *pStr == '\0')  
  28.         return;  
  29.     int number = strlen(pStr);  
  30.     for(int i = 1; i <= number; i++)  
  31.     {  
  32.         vector<char> result;  
  33.         Combination_m(pStr, i, result);  
  34.     }  
  35. }  

第三题------(40分)

1.编写函数对一颗二叉树进行广度遍历——从上往下逐层、同一层从左至右遍历。

2.同为分层遍历,但是先输出最后一层,然后输出倒数第二层,···,最后输出第一层。

分析:1)第一小题是广度优先搜索的一个示例,用一个队列存储节点的话,会发现,如果第k层节点一个都没出队,那么队列中必然没有k+1层节点,而且如果第k层节点刚好都出队了,队列中只有第k+1层节点,且包含所有的k+1层节点。所以从第一层开始,把根节点入队,记录当前层节点数1,然后输出这个层得所有节点,跟新队列,然后正好队列中就只有且包含所有第2层得节点数了,依次类推直到队列为空为止。

2)第二小题可以在遍历的过程中,记录每层元素个数,注意遍历中只入队不出队,每层遍历是否结束,需要多设置一些计数变量。也可使用哑元素的方法,即在每层中间插入NULL,同样,遍历中也是只入队不出对,每层遍历是否结束,需要多设置一些计数变量。

第一小题代码如下:

[cpp]  view plain copy
  1. #include<iostream>  
  2. #include<deque>   
  3. using namespace std;  
  4.   
  5. struct NODE {  
  6.   NODE* pLeft;  
  7.   NODE* pRight;  
  8.   int value;  
  9. };  
  10.   
  11. void PrintTreeByLevel(const NODE* root) {  
  12.   deque<const NODE*> store;  
  13.   int left_num;  
  14.   if(!root)  
  15.     return;  
  16.   store.push_back(root);  
  17.   while(!store.empty()) {  
  18.     left_num = store.size(); // 当前层的节点数  
  19.     while(left_num-- > 0) {  
  20.       const NODE* tmp = store.front();  
  21.       store.pop_front();  
  22.       cout << tmp->value << " ";  
  23.       if(tmp->pLeft)  
  24.         store.push_back(tmp->pLeft);  
  25.       if(tmp->pRight)  
  26.         store.push_back(tmp->pRight);  
  27.     }  
  28.     cout << endl;  
  29.   }  
  30. }  
第二小题代码如下:

[cpp]  view plain copy
  1. void ReversePrintTreeByLevel(const NODE* root) {  
  2.   deque<const NODE*> store;  
  3.   int index = 0; // 遍历元素和哑元素的下标  
  4.   int no = 0; // 遍历过的元素个数   
  5.   if(!root) {  
  6.     return;  
  7.   }  
  8.   store.push_back(root);    
  9.   index = 0;  
  10.   while(index < store.size()) {  
  11.     store.push_back(NULL); // 哑元素   
  12.     while(store[index] != NULL) { // 访问当前层  
  13.       no++;  
  14.       if(store[index]->pRight)  
  15.         store.push_back(store[index]->pRight);  
  16.       if(store[index]->pLeft)  
  17.         store.push_back(store[index]->pLeft);  
  18.       index++;  
  19.     }  
  20.     index++;  
  21.   }  
  22.   for(int i=store.size()-1; i>=0; i--) {  
  23.     if(store[i] == NULL)  
  24.       cout << endl;  
  25.     else {  
  26.       cout << store[i]->value << " ";  
  27.     }  
  28.   }  
  29.   cout << endl;  
  30. }  

今年的题:

一、单选题

1、有变量int i = 0; int a = i++; int b=++a; int c = a+b; 请问表达式 a?b:c 的值是(B)

A0              B1              C2             D3

分析:基础题,考察自加自减运算符和条件运算符。

232位环境下,int *p=new int[10];请问sizeof(p)的值为(A)
A             B10              C40               D8

分析:sizeof每年必考啊,这里其实就是一个指针的大小。


3、有语句char str[] = "abcde";请问表达式sizeof(str)的值是(D)
A1              B4               C5                D6

分析:恩,和上一题对应起来了,这里是串所占空间。

4、有函数int func(int i)的实现为()

int func(int i)

if(i > 1)

return i*func(i-1);

else

return 1;

请问函数调用f(5)的返回值是多少D

A5              B15              C20               D120

分析:阶乘运算,还真有公司愿意年年出-_-||


5、请问以下说法,哪个是正确的(C)

A、每个类都有一个无参数的构造函数

B、每个类都有一个拷贝构造函数

C、每个类能有多个构造函数

D、每个类能有多个析构函数

分析:显然啊。。。不然怎么用多种方式定义新对象


6、用class关键字定义的类,其成员默认的访问属性为(A)

Aprivate         Bprotected      Cpublic           D、无定义


7、类的成员有三种访问属性,分别是publicprotectedprivate,子类能够访问的成员是(B)

A、都能访问

Bpublicprotected

Cpublicprivate

Dprotectedprivate


8、请问对一个排好序的数组进行查找,时间复杂度为(B)

AO(n)            BO(lgn)        CO(nlgn)          DO(1)

分析:咳咳!说明一下,堆排序真心是要注意的一种排序方式,出现频度极高。建议还是拿本算法导论出来啃啃这一节吧,一次掌握,终生受用。一次堆调整或者在排好序的堆内查找都是O(lgn)


9、以下二叉树:

                                      甲

                                    /    \

                                  乙      戊

                                /   \       \

                              丙     丁      己

后序遍历的结果是(C)

A、丙乙丁甲戊己              B、甲乙丙丁戊己              C、丙丁乙己戊甲                  D、丙丁己乙戊甲


10、看以下代码:

A *pa = new A[10];

delete pa;

则类A的构造函数和析构函数分别执行了几次(D)

A1   1          B10   10          C1   10                D10   1


11、看以下代码:

class A

{

public:

~A();

};

A::~A()

{

printf("delete A ");

}

class B : public A

{

public:

~B();

};

B::~B()

{

printf("delete B ");

}

请问执行以下代码

A *pa = new B();

delete pa;

输出的串是(A)

Adelete A       Bdelete B        Cdelete B delete A          Ddelete A delete B


12、文件长度是一个大于0的整数,用变量unsigned file_length来表示,把文件分成块,每块的长度也是一个大于0的整数,用变量unsigned block_length来表示,则文件被分成的块数为(D)

Afile_length/block_length                                            Bfile_length/block_length+1         

C(file_length+block_length-1)/block_length                D((file_length-1)/block_length+1 


13、整数int i = 0xFE78DA45; int k = 0xAC3189B2;i^k的值为(A)

A0x524953f7         B0xAC308800          C0xFE79DBF7           D0X0000001


14、看以下代码:

class parent

{

public:

virtual void output();

};

void parent::output()

{

printf("parent!");

}

class son : public parent

{

public:

virtual void output();

};

void son::output()

{

printf("son!");

}

则以下程序段:

son s;

::memset(&s , 0 , sizeof(s));

parent& p = s;

p.output();

执行结果是(D)

Aparent!       Bson!       Cson!parent!           D、没有输出结果,程序运行出错


15、函数的局部变量所需存储空间,是在哪里分配的(D)

A、进程的数据段      B、进程的栈上    C、进程的堆上       D、以上都可以


16、以下STL的容器存放的数据,哪个肯定是排好序的(D)

Avector        Bdeque         Clist             Dmap


17int a[][3]={{1},{3,2},{6,7,8},{9}};a[2][1]的值是(D)

A3          B6        C2            D7


18、以下关于头文件,说法正确的是(C)

A#include<filename.h>,编译器寻找头文件时,会从当前编译的源文件所在的目录去找

B#includefilename.h,编译器寻找头文件时,会从通过编译选项指定的目录去找

C、多个源文件同时用到的全局整数变量,它的声明和定义都放在头文件中,是好的编程习惯

D、在大型项目开发中,把所有自定义的数据类型、全局变量、函数声明都放在一个头文件中,各个源文件都只需要包含这个头文件即可,省去了要写很多#include语句的麻烦,是好的编程习惯。


19、某棵完全二叉树上有699个节点,则该二叉树的叶子节点数为(B)

A349             B350              C188                D187


20、在一个指向字符串的指针char *p_str,要把字符串中第4个字符的值改为'a',正确的做法是(A)

Ap_str[3]='a'            B*(p_tr+3)='a'       Cp_str[4]='a'       D*(p_tr+4)='a'


二、多选题

1、已知一段文本有1382个字符,使用了1382个字节进行存储,这段文本全部是由abcde5个字符组成,a出现了354次,b出现了483次,c出现了227次,d出现了96次,e出现了232次,对这5个字符使用哈夫曼(Huffman)算法进行编码,则以下哪些说法正确(ACD)

A、使用哈夫曼算法编码后,用编码值来存储这段文本将花费最少的存储空间

B、使用哈夫曼算法进行编码,abcde5个字符对应的编码值是唯一确定的

C、使用哈夫曼算法进行编码,abcde5个字符对应的编码值可以有多套,但每个字符编码的位(bit)数是确定的

Db这个字符的哈夫曼编码值位数应该最短,d这个字符的哈夫曼编码值位数应该最长


2、下列表达式中,不合法的是(AD)

已知:double d = 3.2; int n = 3;

Ad<<2;

Bd/n

C!d && (n-3)

D(d-0.2)|n


3、下面描述正确的是(BC)

Awhile循环语句的循环体至少执行1

Bdo-while循环可以写成while循环的格式

Ccontinue语句可以出现在各种循环体中

Dbreak语句不可以出现在循环体内


4、关于内联函数正确的是(B)

A、类的私有成员函数不能作为内联函数

B、在所有类说明中内部定义的成员函数都是内联函数

C、类的保护成员函数不能作为内联函数

D、使用内联函数的地方会在运行阶段用内联函数体替换掉


5、下面模板声明中,哪些是非法的(BD)

Atemplate<class Type>class C1;

Btemplate<class T,U , class V>class C2;

Ctemplate<class C1 , typename C2>class C3{};

Dtemplate<typename myT , class myT>class C4{};


6、在使用浏览器打开一个网页的过程中,浏览器会使用的网络协议包括(ABC)

ADNS         BTCP        CHTTP            DTelnet


7、下面属于构造散列函数的方法是(ABCD)

A、直接定址法

B、数字分析法

C、乘余取整法

D、平方取中法


8、拷贝构造函数的特点是(BD)

A、该函数名同类名,也是一种构造函数,该函数返回自身引用

B、该函数只有一个参数,必须是对某个对象的引用

C、每个类都必须有一个拷贝初始化构造函数,如果类中没有说明拷贝构造函数,则编译器系统会自动生成一个缺省拷贝构造函数,作为该类的保护成员

D、拷贝初始化构造函数的作用是将一个已知对象的数据成员值拷贝给正在创建的另一个同类的对象


9、下列关于虚函数的说法正确的是(BCD)

A、在构造函数中调用类自己的虚函数,虚函数的动态绑定机制还会生效。

B、在析构函数中调用类自己的虚函数,虚函数的动态绑定机制还会生效。

C、静态函数不可以是虚函数

D、虚函数可以声明为inline


10、下列对函数double add(int a , int b)进行重载,正确的是(ABC)

Aint add(int a ,int b ,int c)

Bint add(double a , double b)

Cdouble add(double a , double b)

Dint add(int a , int b)


笔试题归类总结

        题目如上,分析还未完全做完,下次接着写,先总体分析一下考点吧,并顺带对应一下它们在我之前做的知识总结中的位置(没有的部分说明之前的总结还有一定的疏忽,后期会补上):

1)  二维数组
2)  指针和二维指针
3)  二叉树的三种遍历方式
4)  栈和队列的特性/进出栈序列

5)  运算符执行优先级                                                ----找工作笔试面试那些事儿(1)---C,C++基础和编程风格(2)
6)  内联函数                                                              ----找工作笔试面试那些事儿(4)---C++函数高级特征
7)  构造函数和析构函数                                             ----找工作笔试面试那些事儿(5)---构造函数、析构函数和赋值函数
8)  运算符重载                                                           ----找工作笔试面试那些事儿(4)---C++函数高级特征
9)  多态
10)函数重载                                                               ----找工作笔试面试那些事儿(4)---C++函数高级特征
11)宏的边际效应                                                        ----找工作笔试面试那些事儿(1)---C,C++基础和编程风格(2)
12)sizeof                                                                    ----找工作笔试面试那些事儿(3)---内存管理那些事
13)内存分配相关                                                        ----找工作笔试面试那些事儿(3)---内存管理那些事
14)内存对齐                                                                ----找工作笔试面试补充知识(1)---内存对齐
15)形参和实参
16)结构体和内存
17)程序题里面的递归
18)哈夫曼编码
19)模板
20)网络协议
21)hash相关

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值