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

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

前言:

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

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

一、选择题

#include
void main()
{
       char* a[ ] = { "hello", "the", "world"};

       char** pa = a;

       pa++;

       cout<<”*pa<

A) theworld

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

A) abcdefg

C) adbcfeg
D) abecdfg

分析:

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

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

D) 没有共同点

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

#include 

void main()

{

       int a, x;

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

       {

              a++;

       }

       cout<< a << x <


B) 22
C) 32
D) 41

A)

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

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后没有分号。

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

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

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

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

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

A) 静态数据成员可以在类体内初始化
B) 静态数据成员不可以被类的对象调用
C) 静态数据成员不能受private控制符的作用

A) *
B) >=

D) delete

分析:

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

A) C++语言的多态性分为编译时的多态性和运行时的多态性
B) 编译时的多态性可通过函数重载实现

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

分析:

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

A) e3,e2,e5,e4,e1
B) e2,e3,e5,e4,e1
C) e3,e2,e4,e5,e1

分析:

经常考的一道题,去年微软笔试也考了类似的题目。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出。


B) 类和对象之间的关系是抽象和具体的关系
C) 对象是类的实例,一个对象必须属于一个已知的类
D) 类是具有共同行为的若干对象的统一描述体

A) 在C++语言中数组的名字就是指向该数组第一个元素的指针
B) 长度为n的数组,下标的范围是0-n-1

说明:

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

A) 语句#include “stdlib.h”是正确的,但会影响程序的执行速度
语句#include 是正确的,而且程序执行速度比#include “stdlib.h”要快
C) 语句#include 和#include “stdlib.h”都是正确的,程序执行速度没有区别
D) 语句#include “stdlib.h”是错误的

分析:

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

A) 0
B) 1

D) 7

分析:

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


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

D) 函数名称

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

    else return n+func(n-1);

    return 0;
}
void main()
{

cout<

A) 0
B)10
C)15

  
B)acb
C)cab
D)cba

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

A)一元运算符
B)二元运算符
C)选项A)和选项B)都可能

分析:

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

#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

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

A) 0;
B) 1;

D)以上都不对

分析:

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

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

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

cout << str;

A)xyz123ABC
B)z123ABC
C)xy123ABC

分析:

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

char str[ ] = “xunlei”;

char *p = str;

int n = 10;

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

A) 4, 4, 4

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

分析:

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

char *p, *q;

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

q = p;

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

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


B) abc def
C) abc d
D) d d

分析:

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

struct _THUNDER{

       int iVersion;

       char cTag;

       char cAdv;

       int iUser;

       char cEnd;

}Thunder;

int sz = sizeof(Thunder);

A) 11
B) 12
C) 13

分析:

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

void GetMemeory(char* p)
{
              p = (char*) malloc (100);
}

void test()
{
  char *str=NULL;

  GetMemory(str);

  strcpy(str,”Thunder”);

  strcat(str+2, “Downloader”);

   printf(str);
}

A) Thunder Downloader
B) under Downloader
C) Thunderownloader

分析:

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


B) 5
C) 6
D) 7

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

D) *s.p = 5

A)无确切值

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

分析:

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

A) ab/ab == 1
B) a/bb/a == 1

D) a/b
b == a

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

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

D)NEW是一个结构体变量

A) 9++
B) (x+y)++

D) ++(a-b--)

A) 4
B) 12
C) 28

#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

分析:

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

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

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


B)10,10,10
C)8,8,10
D)8,10,10

分析:

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

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

C) 4
D) 编译错误

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

A) 3
B)4
C) 5

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);

A) 21
B) 22

D) 程序崩溃

分析:

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

A) 关系模型
B) 网状模型

D)以上三个都是

char fun(char *);

main()

{

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

}

A) f1(&a);
B) f1(
s);

D) ch = f1(s);要改成(f1)(s)才正确

int c = 23;

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

A) 0
B) 46

D) 以上都不对

\color{red}{X}}$

二、填空题


knuth(int n, int m)
{
srand((unsigned int)time(0));

for
if ()
{
cout<
}
}

分析:

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)水平有限,暂时想不出比较合理的答案,大家有好方法欢迎留言指教,非常感谢

void prim(int m, int n)
{
if (m>n)
{
while n++;

prim(m,n);

cout< }
}

分析:

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

void perm(int list[], int k, int m)
{
if
{
copy(list,list+m,ostream_iterator(cout," "));

cout<

return;
}
for (int i=k; i<=m; i++)
{
swap(&list[k],&list[i]);

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

分析:

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

三、解答题

\color{red}{有效下载时间是指用户在开始时间和结束时间之间的在线时间,由于用户可能在下载的时候退出迅雷,} \color{red}{每一行代表一个任务记录,记录的字段之间以空格分开。计算每个用户的有效下载时间和总在线时间的比例。}

分析:

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

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

@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的起止时间变换掉,方便处理。

\color{red}{骑士每天可以像国际象棋中的马那样移动一次,可以从中间像8个方向移动(当然不能走出棋盘),} \color{red}{请计算n个骑士的最早聚会地点和要走多少天。要求尽早聚会,且n个人走的总步数最少,}

从键盘输入n(0

分析:

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

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

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

@Kevin_qing 1).求n个点坐标平均值。 记为点c. 2).计算c到各点距离和d0 ,计算点c周围8个点到各点距离d。 如果某个点d

@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).然后把去计算所有骑士走道这些可能的相聚地点所需要的时间,那个相聚点,骑士所需要走的总天数最小。。。。。

#include 
using namespace std;
 
#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
#define ABSOLUTE(a) ( (a) > 0 ? a : -(a) )
 
struct KnightPt
{
    int x;
    int y;
};
 
int knightNumber = 0;//骑士个数
int minGatherDays = 0;//相聚天数
int minWalkDay = 0;
int possibleGatherPtNumber = 0;//相聚地点可能是多个点(1~4),可能相聚地点的个数
int gatherDays[4] = {0};
int walkDays[4] = {0};//每个可能相聚地点的相聚天数
KnightPt kinghtPt[64] = {0};//所有骑士的位置
KnightPt possibleGatherPt[4] = {0};//可能相聚地点的集合
//获取骑士可能相聚的地点的集合
void getPossibleGatherPoint()
{
    int minXPt = 8, minYPt = 8, maxXPt = 0, maxYPt = 0;
    //根据所有骑士的位置,骑士位置X方向最小值和最大值,Y方向最小值和最大值
    for(int i = 0; i < knightNumber; i++)
    {
        if(kinghtPt[i].x < minXPt) minXPt = kinghtPt[i].x;
        if(kinghtPt[i].y < minYPt) minYPt = kinghtPt[i].y;
        if(kinghtPt[i].x > maxXPt) maxXPt = kinghtPt[i].x;
        if(kinghtPt[i].y > maxYPt) maxYPt = kinghtPt[i].y;
    }
    //计算X方向最小值和X方向最大值的中间点,使用float数据类型是因为可能中间点处于棋盘线上。
    //例如X方向最小值为0,X方向最大值为7,中间值就是3.5,位于棋盘线上。同样Y方向同样处理
    float midXPt = minXPt + (float)(maxXPt - minXPt) / 2;
    float midYPt = minYPt + (float)(maxYPt - minYPt) / 2;
    int midXPt0 = (int)midXPt;
    int midXPt1 = (int)(midXPt + 0.5);
    int midYPt0 = (int)midYPt;
    int midYPt1 = (int)(midYPt + 0.5);
    //根据得到的中间点,计算出可能的位置(最多4个),他们都有可能是相聚点。
    possibleGatherPt[possibleGatherPtNumber].x = midXPt0;
    possibleGatherPt[possibleGatherPtNumber].y = midYPt0;
    possibleGatherPtNumber++;
    if(midXPt0 != midXPt1)
    {
        possibleGatherPt[possibleGatherPtNumber].x = midXPt1;
        possibleGatherPt[possibleGatherPtNumber].y = midYPt0;
        possibleGatherPtNumber++;
    }
    if(midYPt0 != midYPt1)
    {
        possibleGatherPt[possibleGatherPtNumber].x = midXPt0;
        possibleGatherPt[possibleGatherPtNumber].y = midYPt1;
        possibleGatherPtNumber++;
    }
    if(midXPt0 != midXPt1 && midYPt0 != midYPt1)
    {
        possibleGatherPt[possibleGatherPtNumber].x = midXPt1;
        possibleGatherPt[possibleGatherPtNumber].y = midYPt1;
        possibleGatherPtNumber++;
    }
}
//获取所有骑士相聚需要走的天数
void getWalkDays()
{
    for(int i = 0; i < possibleGatherPtNumber; i++)
    {
        KnightPt kpt = possibleGatherPt[i];
        for(int j = 0; j < knightNumber; j++)
        {
                     //得到一个骑士要走多少天
            int oneKnightWalkDay = MAX(ABSOLUTE(kinghtPt[j].x - kpt.x), ABSOLUTE(kinghtPt[j].y - kpt.y));
                     //骑士行走的最多天数,为相聚的天数
            gatherDays[i] = MAX(gatherDays[i], oneKnightWalkDay);
                     //获取所有骑士相聚的天数
            walkDays[i] += oneKnightWalkDay;
        }
    }
    
    minGatherDays = gatherDays[0];
    minWalkDay = walkDays[0];
    for(int j = 0; j < possibleGatherPtNumber; j++)
    {
        if(gatherDays[j] < minGatherDays) minGatherDays = gatherDays[j];
        if(walkDays[j] < minWalkDay) minWalkDay = walkDays[j];
    }
}
 
int wmain(wchar_t *argv[], int argn)
{
    cout << "input knight number. range(0 < n <= 64)" << endl;
    cin >> knightNumber;
    cout << "knight all position" << endl;
    for(int i = 0; i < knightNumber; i++)
    {
        cout << "input knight " << i+1 << " position range( 0 ~ 7)" << endl;
        cin >> kinghtPt[i].x;
        cin >> kinghtPt[i].y;
    }
    getPossibleGatherPoint();
    getWalkDays();
 
    for(int k = 0; k < possibleGatherPtNumber; k++)
    {
        if(minGatherDays == gatherDays[k] && minWalkDay == walkDays[k])
        {
            cout << "--------------------------" << endl;
            cout << minGatherDays << " days, all gather can gather" << endl;
            cout << "gather position is x = " << possibleGatherPt[k].x << " y = " << possibleGatherPt[k].y << endl;
            cout << "all knight walk day is " << minWalkDay << endl;
            cout << "--------------------------" << endl;
        }
    }
 
    system("pause");
}

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

\color{red}{请实现以下函数把一个用阿拉伯字符串表示的自然数(串长大于0,小于13,串保证是合法的)} \color{red}{转换成相应的中文字符串。例如1234567890,应输出“十二亿三千四百五十六万七千八百九十” 。 }

分析:

这是一道很经典的题目。犹记得去年博主面有道实习的时候也被问到了这道题目。首先呢,这题用java处理起来还是会比C++在代码上会简洁一些。先看个java版本的吧,话说博主代码能力很水,有问题欢迎大家留言指正,但求轻喷,谢谢。

package com.test;
 
public class NumberProcess  {
 
    private static final String[] UNITS = { "", "十", "百", "千", "万", "十", "百", "千", "亿", "十", "百", "千", };
    private static final String[] NUMS = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九", };
 
    /** 
     *  阿拉伯数字转换成中文字符串 
     *  @param value 要转换的数字 
     *  @return 返回数字转后的中文字符串 
     */
    public static String number2Chinese(int value) {
 
        String result = ""; //转译结果 
 
        for (int i = String.valueOf(value).length() - 1; i >= 0; i--) {
            int r = (int) (value / Math.pow(10, i));//value / Math.pow(10, i) 截位匹配单位 
            result += NUMS[r % 10] + UNITS[i];
        }
 
        result = result.replaceAll("零[十, 百, 千]", "零");//匹配字符串中的 "零[十, 百, 千]" 替换为 "零"
        result = result.replaceAll("零+", "零");//匹配字符串中的1或多个 "零" 替换为 "零"
        result = result.replaceAll("零([万, 亿])", "$1");
        result = result.replaceAll("亿万", "亿"); //亿万位拼接时发生的特殊情况
 
        if (result.startsWith("一十")) { //判断是否以 "一十" 开头 如果是截取第一个字符
            result = result.substring(1);
        }
 
        if (result.endsWith("零")) { //判断是否以 "零" 结尾 如果是截取除 "零" 外的字符
            result = result.substring(0, result.length() - 1);
        }
 
        return result;
    }
 
    public static void main(String[] args) {
        System.out.println(NumberProcess .number2Chinese(1234567890));
    }
}

C++版的一直有些问题,可参照http://lovinchan.iteye.com/blog/266628中编写,等博主整理好了再上来更新。

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


\color{red}{实例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时递归结束。这题有个小问题是这里的“不同”,博主的方法能输出所有结果,但是是不是会有重复(求教)?

//函数功能 : 在字符串中选m个字符
//函数参数 : pStr为字符串,m为选的元素个数,result为选中的字符
//返回值 :   无
void Combination_m(char *pStr, int m, vector &result)
{
    if(pStr == NULL || (*pStr == '\0'&& m != 0))
        return;
    if(m == 0) //递归终止条件
    {
        for(unsigned i = 0; i < result.size(); i++)
            cout< result;
        Combination_m(pStr, i, result);
    }
}

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


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

分析:

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

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

第一小题代码如下:

#include
#include 
using namespace std;
 
struct NODE {
  NODE* pLeft;
  NODE* pRight;
  int value;
};
 
void PrintTreeByLevel(const NODE* root) {
  deque store;
  int left_num;
  if(!root)
    return;
  store.push_back(root);
  while(!store.empty()) {
    left_num = store.size(); // 当前层的节点数
    while(left_num-- > 0) {
      const NODE* tmp = store.front();
      store.pop_front();
      cout << tmp->value << " ";
      if(tmp->pLeft)
        store.push_back(tmp->pLeft);
      if(tmp->pRight)
        store.push_back(tmp->pRight);
    }
    cout << endl;
  }
}

第二小题代码如下:

void ReversePrintTreeByLevel(const NODE* root) {
  deque store;
  int index = 0; // 遍历元素和哑元素的下标
  int no = 0; // 遍历过的元素个数 
  if(!root) {
    return;
  }
  store.push_back(root);  
  index = 0;
  while(index < store.size()) {
    store.push_back(NULL); // 哑元素 
    while(store[index] != NULL) { // 访问当前层
      no++;
      if(store[index]->pRight)
        store.push_back(store[index]->pRight);
      if(store[index]->pLeft)
        store.push_back(store[index]->pLeft);
      index++;
    }
    index++;
  }
  for(int i=store.size()-1; i>=0; i--) {
    if(store[i] == NULL)
      cout << endl;
    else {
      cout << store[i]->value << " ";
    }
  }
  cout << endl;
}

一、单选题

A、0

C、2
D、3

分析:基

础题,考察自加自减运算符和条件运算符。



B、10
C、40
D、8

分析:

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


A、1
B、4
C、5

分析:

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

int func(int i)

if(i > 1)

return i*func(i-1);

else

return 1;

A、5
B、15
C、20

分析:

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

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

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

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

分析:

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


B、protected
C、public
D、无定义

A、都能访问

C、public和private
D、protected和private

A、O(n)

C、O(nlgn)
D、O(1)

分析:

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

                                      甲

                                    /    \

                                  乙      戊

                                /   \       \

                              丙     丁      己

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

D、丙丁己乙戊甲

A *pa = new A[10];

delete pa;

A、1 1
B、10 10
C、1 10

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;


B、delete B
C、delete B delete A
D、delete A delete B

A、file_length/block_length
B、file_length/block_length+1
C、(file_length+block_length-1)/block_length


B、0xAC308800
C、0xFE79DBF7
D、0X0000001

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();

A、parent!
B、son!
C、son!parent!

A、进程的数据段
B、进程的栈上
C、进程的堆上

A、vector
B、deque
C、list

A、3
B、6
C、2

A、#include,编译器寻找头文件时,会从当前编译的源文件所在的目录去找
B、#include“filename.h”,编译器寻找头文件时,会从通过编译选项指定的目录去找
\color{blue}{C、多个源文件同时用到的全局整数变量,它的声明和定义都放在头文件中,是好的编程习惯}
D、在大型项目开发中,把所有自定义的数据类型、全局变量、函数声明都放在一个头文件中,各个源文件都只需要包含这个头文件即可,省去了要写很多#include语句的麻烦,是好的编程习惯。

A、349

C、188
D、187

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


B、(p_tr+3)='a'
C、p_str[4]='a'
D、
(p_tr+4)='a'

二、多选题


B、使用哈夫曼算法进行编码,a、b、c、d、e这5个字符对应的编码值是唯一确定的
\color{blue}{C、使用哈夫曼算法进行编码,a、b、c、d、e这5个字符对应的编码值可以有多套,但每个字符编码的位(bit)数是确定的}


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


B、d/n
C、!d && (n-3)

A、while循环语句的循环体至少执行1次


D、break语句不可以出现在循环体内

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

C、类的保护成员函数不能作为内联函数
D、使用内联函数的地方会在运行阶段用内联函数体替换掉

A、templateclass C1;

C、templateclass C3{};




D、Telnet




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

C、每个类都必须有一个拷贝初始化构造函数,如果类中没有说明拷贝构造函数,则编译器系统会自动生成一个缺省拷贝构造函数,作为该类的保护成员
\color{blue}{D、拷贝初始化构造函数的作用是将一个已知对象的数据成员值拷贝给正在创建的另一个同类的对象}

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


$\color{blue}{D、虚函数可以声明为inline}4



$\color{blue}{C、double add(double a , double b)}4
D、int add(int a , int b)

笔试题归类总结

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





----找工作笔试面试那些事儿(1)---C,C++基础和编程风格(2)
----找工作笔试面试那些事儿(4)---C++函数高级特征
----找工作笔试面试那些事儿(5)---构造函数、析构函数和赋值函数
----找工作笔试面试那些事儿(4)---C++函数高级特征

----找工作笔试面试那些事儿(4)---C++函数高级特征
----找工作笔试面试那些事儿(1)---C,C++基础和编程风格(2)
----找工作笔试面试那些事儿(3)---内存管理那些事
----找工作笔试面试那些事儿(3)---内存管理那些事
----找工作笔试面试补充知识(1)---内存对齐






你可能感兴趣的:(迅雷近几年笔试题及其分析)