百度2015校园招聘软件开发笔试题

首先2015百度校园招聘笔试题目(软开类)奉上:

答案分析(个人所理解的,如有不妥地方还望各位看官指出)

<1>、tcp-ip 连接时3次握手,断开时4次握手。

连接过程:

第一次握手:
客户端发送一个TCP的SYN标志位置1的包指明客户打算连接的服务器的端口,以及初始序号X,保存在包头的序列号(Sequence Number)字段里。

第二次握手:
服务器发回确认包(ACK)应答。即SYN标志位和ACK标志位均为1同时,将确认序号(Acknowledgement Number)设置为客户的I S N加1以.即X+1。

第三次握手.
客户端再次发送确认包(ACK) SYN标志位为0,ACK标志位为1.并且把服务器发来ACK的序号字段+1,放在确定字段中发送给对方.并且在数据段放写ISN的+1。

断开过程:

TCP的连接的拆除需要发送四个包,因此称为四次挥手(four-way handshake)。客户端或服务器均可主动发起挥手动作,在socket编程中,任何一方执行close()操作即可产生挥手操作。

这里分享一个连接讲述的更加详细:http://blog.csdn.net/qq276592716/article/details/19762121

<2>、内存管理淘汰算法(更加详细内容见:http://www.haogongju.net/art/1699130

1. FIFO先进先出的算法

FIFO算法总是选择在内存驻留时间最长的一页将其淘汰。FIFO算法认为先调入内存的页不再被访问的可能性要比其他页大,因而选择最先调入内存的页换出。实现FIFO算法需要把各个已分配页面按分配时间顺序记录在一个数组中,每次淘汰最早进入数组的页。

2. OPT最佳淘汰算法描述:

该算法淘汰在访问串中将来最不常用的页。这样,淘汰掉该页将尽量减少因需要访问该页又立即把它调入的现象。遗憾的是,这种算法无法实现,因为它要求必须预先知道每一个进程的访问串。

3. LRU最近最少使用算法

LRU工作原理是,当需要淘汰某页,选择离当前时间最近的一段时间内最久没有使用过的页先淘汰。在这里采用一个页面集大小的栈存储最近访问的页面。页面按时间顺序压如栈中。如果被访问的页在栈中,则从栈中移出页面,压入栈顶。这样栈底记录离当前时间最近的一段时间内最久没有使用过的页。

4. LFU最少访问页面算法

LFU在需要淘汰某一页时,首先淘汰到当前时间为止、被访问次数最少的那一页。这只要在页面集中给每一页增设一个访问计数器即可实现。每当该页被访问时,访问计数器加1,而发生一次缺页中断时,则淘汰计数值最小的那一页,并将所有的计数器清零。

5. NUR最近最不经常使用算法

NRU在需要淘汰某一页时,从那些最近一个时期内未被访问的页中任选一页淘汰。只要在页表中增设一个访问位即可实现。当某页被访问时,访问位置1。否则,访问位置0。系统周期性地对所有引用位清零。当需淘汰一页时,从那些访问位为零的页中选一页进行淘汰。如果引用位全0或全1,NRU算法退化为FIFO算法。

<3>、数据库范式,这里自我感觉三大范式即可(更加详细内容:http://ce.sysu.edu.cn/cdbm/news/coures/200908/news_20090807210925_242.html

1 第一范式(1NF)

    在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。 
    所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。例如,对于图3-2 中的员工信息表,不能将员工信息都放在一列中显示,也不能将其中的两列或多列在一列中显示;员工信息表的每一行只表示一个员工的信息,一个员工的信息在表中只出现一次。简而言之,第一范式就是无重复的列。

2 第二范式(2NF)

    第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。如图3-2 员工信息表中加上了员工编号(emp_id)列,因为每个员工的员工编号是惟一的,因此每个员工可以被惟一区分。这个惟一属性列被称为主关键字或主键、主码。 
第二范式(2NF)要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。简而言之,第二范式就是非主属性非部分依赖于主关键字。

3 第三范式(3NF) 

    满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。例如,存在一个部门信息表,其中每个部门有部门编号(dept_id)、部门名称、部门简介等信息。那么在图3-2的员工信息表中列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中。如果不存在部门信息表,则根据第三范式(3NF)也应该构建它,否则就会有大量的数据冗余。简而言之,第三范式就是属性不依赖于其它非主属性。

二、编程设计和算法题目

<1>在一个单向链表中返回其中项,并分析复杂度。

分析:可以借助于两个指针,快慢指针,快指针一次走两步,慢指针一次走一步,当快指针走到尾端时,慢指针即指向中项位置。空间复杂度为0(1)时间复杂度为O(n).

struct ListNode
{
    struct ListNode *next;
    int key;
};

ListNode* getMID(ListNode* head)
{
    if (NULL == head)return NULL;
    ListNode *first = head;
    ListNode *second = head;
    while(NULL != second->next)
    {
        if(NULL == second->next->next)break;
        first = first->next;
        second = second->next;
    }
    return first;
}
View Code

<2>在一个集合S中找出最大元素C使得C=A+B,其中A,B均属于集合S。分析复杂度。

分析:1、首先对集合进行排序,从小到大排序,可选排序算法较快的n*log(n)的快排、归并、堆排序等。

2、找最大满足条件的元素C。两层循环,外层循环从大到小依次寻找C。内层循环,分别从头尾向中间寻找元素A B,是的 C = A + B,找到后即跳出两层循环。时间复杂度O(n^2)。

总体复杂度为 n*log(n)+O(n^2) = O(n^2)。

int cmp(const void *a,const void *b)
{
    int *num1 = (int *)a;
    int *num2 = (int *)b;
    return *num2 - *num1;
}

int  getMAXElement(int *arr,int len)
{
    bool flag = false;//标志位,标志着是否找到C
    //快排,这里直接调用库函数中的快排算法
    qsort(arr,len,sizeof(int),cmp);
    int k = 0;
    for (k = len-1; k >1; k++)
    {
        for (int i = 0,j = k-1; i < j;)
        {
            int temp = arr[i] + arr[j];
            if (temp == arr[k])
            {
                flag = true;
                break;
            }
            if (temp < arr[k])
            {
                i++;
                continue;
            }
            if (temp > arr[k])
            {
                j--;
                continue;
            }
        }
        if (flag)break;
    }
    if (flag)
    {
        return arr[k];
    }
    else return -1;//标志着没找到
}
View Code

 

<3>使用栈先进后出来模拟队列先进先出的结构,实现函数:enqueue(入队),dequeue(出队),isEmpty(是否为空)的判断。

分析:使用栈来模拟队列,需要借助两个栈A、B来实现,A栈负责入队,B栈负责出队,空值判断时需要判断两个栈均为空。需要注意的是,从A栈向B栈移动元素时要注意只有当B栈为空时,把A栈内所有元素一次性移入B栈,若B栈有元素,那么不可移动,需要等待B栈为空时才可以移动。

stack<int> A;
stack<int> B;
//入队
void enqueue(int value[],int len)
{
    for (int i = 0; i < len; i++)
    {
        A.push(value[i]);
    }
    if (B.empty())
    {
        while(!A.empty())
        {
            B.push(A.top());
            A.pop();
        }
    }
}
出队
void dequeue()
{
    while(!B.empty())
    {
        B.pop();
        //其他操作
    }    
    while(!A.empty())
    {
        B.push(A.top());
        A.pop();
    }
    while(!B.empty())
    {
        B.pop();
        //其他操作
    }
}
//判断是否为空
bool isEmpty()
{
    if(A.empty() && B.empty())return true;
    return false;
}
View Code

这里我就懒得再举例子做测试用例,自我感觉代码应该可以通过,如果有什么错误之处还望指出。O(∩_∩)O谢谢!

 

三、系统设计题

我表示不会哦。。。。。。。。。。哪位大神有此题解法,可以分享下就好了。以后我若有机会看到这题的解法我会在更新的。。。。。

 

posted on 2014-09-15 10:12  NewPanderKing  阅读(23916)  评论(1编辑  收藏  举报

导航