百度笔试2

来源:互联网 发布:狗和狼的区别知乎 编辑:程序博客网 时间:2024/05/19 22:55

  前段时间百度3面后,就没有然后了........我就当他默拒了吧,LM3面后和4面的通知时间隔了差不多1个月,我估计3周了,老子怒了,是死是活起码要给个交代吧........

       天天又进入了堕落的循环,哎,杯具啊,发现自己不是那种细水长流型的选手,不能长期坚持学习,总是学习的时候玩命的学习,不分昼夜,各种研究,各种钻研,一直学到吐......玩起来的时候也同样是的......我的性格为什么会是这样......郁闷

       昨天大三的阿牛让我给他百度的暑期实习生在线笔试帮帮忙,毕竟是过了百度3次面试的人,起码有点点经验,平时关系不错,他是我一直看着成长起来的,6点开始,一直踢实况提到五点半,惊奇的发现时间快到了,急急忙忙的准备。关了游戏,开了vc,取了笔和纸,一想到自己没吃晚饭,要做2个小时马上又洗了个苹果充饥。然后就坐在电脑前发呆,等到6点阿牛把题目发过来。

      看到笔试题目后,扫了一眼,前面是两道问答题,一看都会,而且觉得不是一般的简单。马上对阿牛说我做这两道题,让他看后面的两道编程题。10分钟搞定后开始看编程题了,第二道编程题是道关于树的性质的题目,我看了看presentation,估计百度内部有个OJ,直接提交判断的,考研的时候无意中看到过类似的,我问了问阿牛开始写了没,他说还在思考,于是我说我来写吧,写了20多分钟,第一个版本的完成了,我让阿牛写测试数据。自己去看第一道编程题,估计百度的题目设计是由易到难,第一题只要求写思路,不要求代码实现。额,估计RP吧,这道题是我前面准备ACM的时候一种算法类型的一个子模块。5分钟搞定吧,自己写了思路,把原来的代码翻了翻,5分钟全部搞定了,估计不会的人现场推是O(n^2),我的算法差不多O(1)。

       这个时候阿牛发来信息,说我的程序有问题,有错误。我对我自己的算法还是有信心的,在保证完备性的基础上压缩到了O(n),而且能优化的地方全部都非常优化了,逻辑性也非常强,调试的时候还是非常顺手,阿牛的测试用例也很不错,改了2次,都是小毛病。

       这个时候估计1小时15分钟了,还差一道题。阿牛说自己去搜,我就没管了。自己从头到尾看了看自己的解答,估计能把他送进面试吧,呵呵。

        我发下昨天的题目和自己的解答吧,大牛们就不要看了,BS下我吧,题目确实水,而且不是一般的水.........有点累了,今天下午踢球了。最后一题没看,有兴趣的同志们可以看看,最后一题听说一个从百度实习回来的一点儿思路都没有.......

第一题     简答

1. 简要说明树的深度优先、广度优先遍历算法,及非递归实现的特点。
深度优先搜索的基本思想是顺着某一个路径垂直往下搜索,每次都选择当前节点的某个子节点作为下一个处理节点,当达到叶子节点的时候,再回溯回到上一个节点,一直到所有的节点都被访问
特点:写深搜的时候要注意递归的跳出条件和回溯的状态恢复,再就是尽可能的找出所有的剪枝条件。
广度优先搜索的基本思想是一层一层的搜索,遍历到某一个节点的时候,将该节点的所有子节点都放入队列中,用以下一层访问
特点:广度优先的时候,注意存储层数,让遍历的搜索策略尽量走向目标状态,减少遍历中访问的节点数目。
非递归的实现:深搜用到栈来辅助实现,广搜用到队列作为辅助工具,都用一个bool数组存储是否节点访问过


2. 在处理磁盘数据时,需要首先将其读入内存才能进行处理。如果要读取的数据已经在内存中,则可以直接访问内存。通常来说内存是有限的,因此要读取新的数据时必须覆盖内存中一部分原有的数据。假设现在有n块同样大小的数据,内存一共可以容纳m块数据。现在给出一系列对这些数据的读取请求,要求它们必须按照给定的顺序被读取,同时要求读取磁盘的次数尽可能地少。请简述一个策略满足这样的要求。
最近最少使用的策略
基本思路:用最近的一段时间内块的访问率来预测接下来各个块的被访问概率。
实现步骤:用一个长度为n的双向队列来模拟访问,队尾插入,对头释放。当队列空间<n的时候,先填满n,也就是将n个数据块放入内存。1当内存没有满而且访问的数据在内存中,也就是队列长度<n的时候,将被访问的数据块调整到插入数据的队尾。2当内存满了而且要访问的数据不再内存中的时候,需要置换数据块,选择对头的数据块置换出去。

第二题 算法与程序设计

1.百度全体员工玩分组游戏,前面五分钟大家分头找队友,并将每个人找到的队友信息汇报给主持人,如果A和B是队友,B和C是队友,那么A和C也是队友;接着主持人不断地随机抽取两个人,希望判断二者是否为队友。请设计一个计算机程序辅助主持人判断两个人是否为队友,说明程序的关键算法,不需要代码实现。

例如:

<小明,小王>,<小军,小王>,<小丽,小李>是队友,那么小军和小明是队友,小军和小丽不是队友。

关键思路:类似判断图的连通性
1 构图
用hash表存储名字,并且用数字来代替。<小明,小王>,<小军,小王>,<小丽,小李> -> <1,2> , <3,2>, <4,5>
2 简化
将这些序列的输入全部变成格式化的<a,b> a<b的输入形式,因为判断小明和小王是不是队友的时候<小明,小王> <小王,小明>意义是一样的,不影响算法正确性
3 算法描述
一开始的时候每个名字都是一个独立的节点,随着两个是不是队友的输入,建立关系,也就是连接两个节点的边。
当需要查询的时候,看两个节点是不是可达的就可以直接判断出来。
4 代码实现 keyword:并查集

int parent[200]={0},rank[200]={0};

struct BCSet
{
void makeSet(int i)
{
   parent[i]=i;
}
int findSet(int i)
{
   if(parent[i]!=i)
   {
    parent[i]=findSet(parent[i]);
   }
   return parent[i];
}
void unionSet(int i, int j)
{
   if(rank[i]>rank[j])
   {
    parent[j]=i;
   }
   else if(rank[i]<rank[j])
   {
    parent[i]=j;
   }
   else
   {
    rank[j]++;
    parent[i]=j;
   }
}
};
一开始将所有的人名makeSet。
输入关系的时候两两unionSet。
查询是否为队友的时候两两findSet,看是否相同
5 算法效率分析
我的代码里面查找时候用了回溯,所以每次新合并后的都会自动调整parent,时间差不多O(1).

2.给定以下二叉树:

struct node_t

{

    node_t *left, *right;

    int value;

};

要求编写函数 node_t* foo(node_t *node, unsigned int m, unsigned int k);

输出以 node 为根的二叉树第 m 层的第 k 个节点值.

(level, k 均从 0 开始计数)

注意:

1) 此树不是完全二叉树;

2) 所谓的第K个节点,是本层中从左到右的第K个节点


代码:
#include<iostream>
using namespace std;

struct node_t
{
    node_t *left, *right;
    int value;
};

node_t* queue[10000];
int head,tail;

//思路:一层一层遍历,当到第m层的时候,若该层的节点数目>=k+1,则输出
node_t* foo(node_t *node, unsigned int m, unsigned int k)
{
//invalid input
if(node==NULL)
   return NULL;

//initial queue
head=tail=0;

int level,start,level_sum,i,current_level_sum;

//从第一层开始
level_sum=1;
level=0;
queue[tail++]=node;

//先遍历完前m-1层,存储第m层的节点
while(level<m && head<tail)
{
   current_level_sum=0;
   for(i=0; i<level_sum && head<tail; i++)
   {
    //如果是叶子节点,别忘了head++
    if(queue[head]->left==NULL && queue[head]->right==NULL)
    {
     head++;
     continue;
    }

    if(queue[head]->left)
    {
     queue[tail++]=queue[head]->left;
     current_level_sum++;
    }
    if(queue[head]->right)
    {
     queue[tail++]=queue[head++]->right;
     current_level_sum++;
    }
   }
   //一层访问完毕,重置遍历变量
   level_sum = current_level_sum;
   level++;
}

//总的层数不足m
if(head==tail)
   return NULL;

//第m层节点不足k个
if(tail-head-1<k)
   return NULL;

    //直接返回第k个
return queue[head+k];
}

int main()
{

    //自己想的测试用例
struct node_t five = {NULL, NULL, 5 } ;
struct node_t four = {NULL, NULL, 4 } ;
struct node_t three = {NULL, NULL, 3 } ;
struct node_t two =   {&four, &five, 2 } ;
struct node_t one =   {&two, &three, 1 } ;

struct node_t *node_result = (struct node_t *)malloc( sizeof(struct node_t) ) ;
node_result = foo( &one, 0, 0 ) ;
cout << node_result->value << endl ;
node_result = foo( &one, 1, 0 ) ;
cout << node_result->value << endl ;
node_result = foo( &one, 1, 1 ) ;
cout << node_result->value << endl ;
node_result = foo( &one, 2, 0 ) ;
cout << node_result->value << endl ;
node_result = foo( &one, 2, 1 ) ;
cout << node_result->value << endl ;

return 0;
}

第三题 系统设计题

在一个复杂广告系统中,需要很多系统协同工作,其中包括众多定时任务(最初配置在linux crontab中调度\管理)的相互依赖,例如:A任务是一个每天定时处理日志的计算任务、B任务是一个反作弊任务,B任务需要读取A任务产生的结果文件, A、B任务由于系统资源限制、运行在不同物理机器上。在这样一个环境中,为了保障这些任务的有序调度和运行,需要一个任务调度系统存在。这里请设计一个任务调度系统来取代原始的linux crontab模式。(提示:调度系统中尽量不要存在单点,如果存在单点、则请指出优缺点对比;任务之间的依赖关系需要机制来严格保证;)

根据以上背景完成如下问题:


1、给出一个系统整体结构图,并简要描述系统各个部份功能、整体调度运行流程;

2、任务调度系统中需要管理上千个定时任务,每个定时任务需要一个数据结构来描述,请用C结构体语法描述一个任务单元、并注释每个结构体成员的含义;


原创粉丝点击