百度暑期实习生笔试题数据挖掘方向.docx

上传人:b****1 文档编号:2393973 上传时间:2023-05-03 格式:DOCX 页数:60 大小:202.60KB
下载 相关 举报
百度暑期实习生笔试题数据挖掘方向.docx_第1页
第1页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第2页
第2页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第3页
第3页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第4页
第4页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第5页
第5页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第6页
第6页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第7页
第7页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第8页
第8页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第9页
第9页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第10页
第10页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第11页
第11页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第12页
第12页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第13页
第13页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第14页
第14页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第15页
第15页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第16页
第16页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第17页
第17页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第18页
第18页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第19页
第19页 / 共60页
百度暑期实习生笔试题数据挖掘方向.docx_第20页
第20页 / 共60页
亲,该文档总共60页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

百度暑期实习生笔试题数据挖掘方向.docx

《百度暑期实习生笔试题数据挖掘方向.docx》由会员分享,可在线阅读,更多相关《百度暑期实习生笔试题数据挖掘方向.docx(60页珍藏版)》请在冰点文库上搜索。

百度暑期实习生笔试题数据挖掘方向.docx

XX暑期实习生笔试题数据挖掘方向

1.单词a中任意字母交换位置变为单词b,我们就称单词a,b为兄弟单词,如army与mary为兄弟单词。

现给一个单词字典,用户输入一个单词,找出字典中所有的兄弟单词,请写出你的解题思路和算法。

 

答:

我有两个思路 

      思路一:

是对输入的单词进行全排列,对每一种排列在字典里查询,统计查到的兄弟单词个数。

(但是这个思路有个问题,就是单词的字母太多的时候,排列情况非常多,查询时间复杂度很大) 

      思路二:

将字典里的所有单词按字母顺序重新组成单词,如army和mary都变成amry,那么所有兄弟单词都变成同样的单词。

再对这些变化过后的单词做hash映射,再对输入的单词做同样的映射,就可以很快查询出所有兄弟单词,查询的时间复杂度为O

(1) 

  

2.线程和进程有什么区别,“线程安全”怎么理解?

 

      (这是考操作系统里的线程和进程的相关知识,很多书中都有答案) 

  

3.c与c++分别是怎样动态分配和释放内存的,有什么区别?

 

      (这个题也是概念题,从书中或者网上找答案吧) 

  

4.网页爬虫,即从一个网页开始,查找出该页的所有url网址,并进入这些url,如此循环,直到某个时候连接回来或者到某个空白页为止。

将这些连接url一一连接起来。

为了简单起见,假设每个网页里都只有一个url,从两个网页入口开始,做上述操作,那么将形成两个单向链表。

请判断这两个爬虫里有没有相同的url。

(大概是这样的) 

  答:

其实这就是变相的问,两个单向链表有没有相交。

我有两种思路 

      思路一:

如果两个单身链表相交,那么从相交节点开始,后面的节点完全重合,直到链表末尾(这个可以自己画一下,因为是单向链表)。

所以用两个指针分别指向两个链表头节点,从头节点开始依次往后直到指向链表末尾,然后判断两个指针是不是指向同一个节点,如果是,那么就有相同的url。

 

      思路二:

将其中一个链表(L1)的末尾指向另一个链表(L2)的头节点,然后从L1的头节点开始往后遍历每个节点,并留下访问过的标记。

如果有相交,那么肯定会形成一个环,所以如果检测到有环的话,说明有相同的url。

 

  

5.数组al[0...num-1]可以分为两部分,al[0...mid-1]和al[mid...num-1],并且这两部分都各自有序。

请将数组两部分merge(合并),形成一个总体有序的数组,并且要求空间复杂度为O

(1)。

 

  答:

这个题如果没有要求空间复杂度,那么很容易想到用归并排序,但是是要另外开辟一个同样大小的数组,所以不行。

其实这个题要求空间复杂度为O

(1),就是说不能另外开辟空间,我的方法是将al[mid...num-1]的每个元素插入到al[0...mid-1]里,先在前部分,找到待插入元素的位置,然后将要插入的元素保存到一个变量里,然后从待插入的位置开始把后面的元素依次往后移动一格,腾出位置,最后将保存下来的元素插入到该位置,最终形成一个整体有序的数组。

 

  

6.是一个关于XX搜索中的suggestion的东东,也就是你在搜索框里输入某个字,会有提示相关的语句的下拉列表。

比如说输入“北京”,那么会提示“北京地铁”、“北京天安门”...。

请问这是怎么实现的,写出相应的数据结构和思路,要求效率尽可能高,有没有新的方法提高效率。

 

  (这个题我没怎么答出来,就是写了一下思路,用字典树记录用户搜索的词频,然后统计出词频最高的几条进行提示,不知道对不对)

1.单词a中任意字母交换位置变为单词b,我们就称单词a,b为兄弟单词,如army与mary为兄弟单词。

现给一个单词字典,用户输入一个单词,找出字典中所有的兄弟单词,请写出你的解题思路和算法。

   答案:

 

 (思路一)计算ASCII码,如果值与输入词的ASCII码相等,再判断;

 (思路二)是对输入的单词进行全排列,对每一种排列在字典里查询,统计查到的兄弟单词个数。

(但是这个思路有个问题,就是单词的字母太多的时候,排列情况非常多,查询时间复杂度很大) 

 (思路三)将字典里的所有单词按字母顺序重新组成单词,如army和mary都变成amry,那么所有兄弟单词都变成同样的单词。

再对这些变化过后的单词做hash映射,再对输入的单词做同样的映射,就可以很快查询出所有兄弟单词,查询的时间复杂度为O

(1)

 

2. 线程和进程有什么区别,“线程安全”怎么理解?

   答案:

   线程是指进程内的一个执行单元,也是进程内可调度的实体。

   与进程的区别:

   1)地址空间:

进程内的一个执行单元;

                进程至少有一个线程;

                它们共享进程的地址空间;

                而进程有自己独立的地址空间;

   2)线程是处理器调度的基本单位,但进程不是;

   3)线程是处理器调度的基本单位,但进程不是;

   4)二者均可并发执行。

     进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。

     线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。

      如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。

如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

     或者说:

一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。

  线程安全问题都是由全局变量及静态变量引起的。

     若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。

 

3.c与c++分别是怎样动态分配和释放内存的,有什么区别?

    答案:

    c语言提供内存动态分配的函数有:

malloc、calloc、realloc,在使用这些函数时必须包含其头文件,分别为:

     1)malloc函数:

void*malloc(unsignedintsize)

     在内存的动态分配区域中分配一个长度为size的连续空间,如果分配成功,则返回所分配内存空间的首地址,否则返回NULL,申请的内存不会进行初始化。

     2)calloc函数:

void*calloc(unsignedintnum,unsignedintsize)

     按照所给的数据个数和数据类型所占字节数,分配一个num*size连续的空间。

     calloc申请内存空间后,会自动初始化内存空间为0,但是malloc不会进行初始化,其内存空间存储的是一些随机数据。

     3)realloc函数:

void*realloc(void*ptr,unsignedintsize)

     动态分配一个长度为size的内存空间,并把内存空间的首地址赋值给ptr,把ptr内存空间调整为size。

     申请的内存空间不会进行初始化。

 

    用c语言提供的这些动态内存分配函数后,对于这些已经申请的内存空间需要你自己进行释放。

如果你没有释放,并且你只是随便运行一下自己的一个很小的程序,可能不会产生什么很大的影响。

但是,如果这样一个大型程序或软件运行中调用了这些语句,而没有对申请的内存进行释放,那么后果是很严重的。

    因此,在我们平时写程序的过程中,应该养成好的变成习惯。

在使用了这些函数动态分配了一段内存后,要记得对其进行释放。

    释放的函数为free函数:

 

    free函数原型为:

voidfree(void*ptr)

    作用:

释放由上面3种函数所申请的内存空间。

    参数:

ptr:

指向需要释放的内存空间的首地址。

 

   在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。

   申请和释放堆中分配的存储空间,分别使用new和delete的两个运算符来完成:

   指针变量名=new类型名(初始化式);

   delete指针名;

   例如:

     int*pi=newint(0)

4、网页爬虫,即从一个网页开始,查找出该页的所有url网址,并进入这些url,如此循环,直到某个时候连接回来或者到某个空白页为止。

将这些连接url一一连接起来。

为了简单起见,假设每个网页里都只有一个url,从两个网页入口开始,做上述操作,那么将形成两个单向链表。

请判断这两个爬虫里有没有相同的url。

(大概是这样的) 

    答案:

    其实这就是变相的问,两个单向链表有没有相交。

我有两种思路 

     思路一:

如果两个单身链表相交,那么从相交节点开始,后面的节点完全重合,直到链表末尾(这个可以自己画一下,因为是单向链表)。

所以用两个指针分别指向两个链表头节点,从头节点开始依次往后直到指向链表末尾,然后判断两个指针是不是指向同一个节点,如果是,那么就有相同的url。

 

     思路二:

将其中一个链表(L1)的末尾指向另一个链表(L2)的头节点,然后从L1的头节点开始往后遍历每个节点,并留下访问过的标记。

如果有相交,那么肯定会形成一个环,所以如果检测到有环的话,说明有相同的url。

     具体思路见我的博文《寻找两个单链表的第一个公共节点》

 

5.数组al[0...num-1]可以分为两部分,al[0...mid-1]和al[mid...num-1],并且这两部分都各自有序。

请将数组两部分merge(合并),形成一个总体有序的数组,并且要求空间复杂度为O

(1)。

 

   答案:

   这个题如果没有要求空间复杂度,那么很容易想到用归并排序,但是是要另外开辟一个同样大小的数组,所以不行。

其实这个题要求空间复杂度为O

(1),就是说不能另外开辟空间,我的方法是将al[mid...num-1]的每个元素插入到al[0...mid-1]里,先在前部分,找到待插入元素的位置,然后将要插入的元素保存到一个变量里,然后从待插入的位置开始把后面的元素依次往后移动一格,腾出位置,最后将保存下来的元素插入到该位置,最终形成一个整体有序的数组。

 

 

6.是一个关于XX搜索中的suggestion的东东,也就是你在搜索框里输入某个字,会有提示相关的语句的下拉列表。

比如说输入“北京”,那么会提示“北京地铁”、“北京天安门”...。

请问这是怎么实现的,写出相应的数据结构和思路,要求效率尽可能高,有没有新的方法提高效率。

 

 

7、一个长方形框,里面嵌套n个长方形框,这些长方形框只能是全部水平排列或是全部垂直排列,同样里面的长方形框还能嵌套其他长方形框,规则同上,最里面的长方形框内有n个数据(n>=0),垂直化一条线,能穿过的数字序列 

(1)求两个数列是否能在一条直线上 

(2)求出所有能在一条线上的字符序列(不知道这样解释大家清楚不,有拍照的同学上传张照片,我本想拍叫那监考MM看见了,就一直呆在我旁边,没机会拍) 

  思路:

  

(1)判断两个数所属的同一层次的相同矩形框的下一层次矩形框是水平排列的还是垂直排列的,垂直排列在能在一条线上,水平排列则不能。

  

(2)用回溯算法求出所有在一条直线上的字符串,用两字符串是否在同一直线上进行剪枝操作 

 

8、就是词义相似度

题目:

两个单向链表,找出它们的第一个公共结点。

链表的结点定义为:

structListNode

{

      int       m_nKey;

      ListNode*  m_pNext;

};

分析:

这是一道微软的面试题。

微软非常喜欢与链表相关的题目,因此在微软的面试题中,链表出现的概率相当高。

如果两个单向链表有公共的结点,也就是说两个链表从某一结点开始,它们的m_pNext都指向同一个结点。

但由于是单向链表的结点,每个结点只有一个m_pNext,因此从第一个公共结点开始,之后它们所有结点都是重合的,不可能再出现分叉。

所以,两个有公共结点而部分重合的链表,拓扑形状看起来像一个Y,而不可能像X。

看到这个题目,第一反应就是蛮力法:

在第一链表上顺序遍历每个结点。

每遍历一个结点的时候,在第二个链表上顺序遍历每个结点。

如果此时两个链表上的结点是一样的,说明此时两个链表重合,于是找到了它们的公共结点。

如果第一个链表的长度为m,第二个链表的长度为n,显然,该方法的时间复杂度为O(mn)。

接下来我们试着去寻找一个线性时间复杂度的算法。

我们先把问题简化:

如何判断两个单向链表有没有公共结点?

前面已经提到,如果两个链表有一个公共结点,那么该公共结点之后的所有结点都是重合的。

那么,它们的最后一个结点必然是重合的。

因此,我们判断两个链表是不是有重合的部分,只要分别遍历两个链表到最后一个结点。

如果两个尾结点是一样的,说明它们用重合;否则两个链表没有公共的结点。

在上面的思路中,顺序遍历两个链表到尾结点的时候,我们不能保证在两个链表上同时到达尾结点。

这是因为两个链表不一定长度一样。

但如果假设一个链表比另一个长l个结点,我们先在长的链表上遍历l个结点,之后再同步遍历,这个时候我们就能保证同时到达最后一个结点了。

由于两个链表从第一个公共结点考试到链表的尾结点,这一部分是重合的。

因此,它们肯定也是同时到达第一公共结点的。

于是在遍历中,第一个相同的结点就是第一个公共的结点。

在这个思路中,我们先要分别遍历两个链表得到它们的长度,并求出两个长度之差。

在长的链表上先遍历若干次之后,再同步遍历两个链表,知道找到相同的结点,或者一直到链表结束。

此时,如果第一个链表的长度为m,第二个链表的长度为n,该方法的时间复杂度为O(m+n)。

基于这个思路,我们不难写出如下的代码:

 

viewplain

1.template  

2.struct ListNode  

3.{  

4.    T data;  

5.    ListNode* pNext;  

6.};  

7.template int GetListLength(ListNode* pHead)  

8.{  

9.    int nLength = 0;  

10.    while(pHead)  

11.    {  

12.        ++nLength;  

13.        pHead = pHead->pNext;  

14.    }  

15.    return nLength;  

16.}  

17.template  

18.ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2)  

19.{  

20.    int nLength1 = GetListLength(pHead1);  

21.    int nLength2 = GetListLength(pHead2);  

22.  

23.    // 交换两链表,是1为较长的链表  

24.    if(nLength1 < nLength2)  

25.    {  

26.        ListNode* pTemp = pHead1;  

27.        pHead1 = pHead2;  

28.        pHead2 = pTemp;  

29.    }  

30.    for(int i = 0; i < nLength1 - nLength2; ++i)  

31.    {  

32.        pHead1 = pHead1->pNext;  

33.    }  

34.    while(pHead1 && pHead1 !

= pHead2)  

35.    {  

36.        pHead1 = pHead1->pNext;  

37.        pHead2 = pHead2->pNext;  

38.    }  

39.  

40.    return pHead1;  

41.}  

 

PS:

两个有公共结点而部分重合的链表,拓扑形状看起来像一个Y,而不可能像X。

即从公共节点开始之后的所有都相同!

求出链表长度差,遍历差数目长的链表,之后同步遍历两链表,第一个相同的节点即是结果。

 

PS:

另外一种方法是把在一个链表尾部插入另一个链表,然后判断合成的新链表是否有环。

环入口即为第一个公共点。

上题是基于两个链表无环考虑的。

1)判断一个链表是否有环。

设置两个指针(fast,slow),初始值都指向头,slow每次前进一步,fast每次前进二步,如果链表存在环,则fast必定先进入环,而slow后进入环,两个指针必定相遇。

(当然,fast先行头到尾部为NULL,则为无环链表)

viewplain

1.// 判断链表是否有环  

2.template  

3.bool HasRing(ListNode* pHead)  

4.{  

5.    ListNode* pFast = pHead;  

6.    ListNode* pSlow = pHead;  

7.    while(pFast && pFast->pNext)  

8.    {  

9.        pSlow = pSlow->pNext;  

10.        pFast = pFast->pNext->pNext;  

11.  

12.        if(pSlow == pFast) break;  

13.    }  

14.  

15.    return !

pFast && !

pFast->pNext;  

16.}  

 

2)确定环入口:

当fast若与slow相遇时,slow肯定没有走遍历完链表,而fast已经在环内循环了n圈(1<=n)。

假设slow走了s步,则fast走了2s步(fast步数还等于s加上在环上多转的n圈),设环长为r,则:

2s=s+nr

s=nr

设入口环与相遇点距离为x,x

a=s-x=(n-1)r+(r-x),而r-x即为fast再次到环入口点时的步数

由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点,于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。

 

 

viewplain

1.// 判断链表环入口,如果没有环,返回NULL  

2.template  

3.ListNode* FindRingEntrance(ListNode* pHead)  

4.{  

5.    ListNode* pFast = pHead;  

6.    ListNode* pSlow = pHead;  

7.  

8.    // 先找到相遇点  

9.    while(pFast && pFast->pNext)  

10.    {  

11.        pSlow = pSlow->pNext;  

12.        pFast = pFast->pNext->pNext;  

13.        if(pSlow == pFast) break;  

14.    }  

15.  

16.    // 一个从起点,一个从相遇点重新遍历,步长相同,当再次相遇时,就是环入口  

17.    pSlow = pHead;  

18.    while(pFast && pFast !

= pSlow)  

19.    {  

20.        pSlow = pSlow->pNext;  

21.        pFast = pFast->pNext;  

22.    }  

23.  

24.    return pFast;  

25.}  

 

3)如过两个链表可能有环,如何判断两个链表是否相交?

以及找到两个链表的第一个公共点?

 

如果两个有环的链表相交,那么它们的环必定为公共环。

如果交点不在环上,第一个公共点就是第一个交点。

但是如果交点在环上,环的入口点不同。

那么就以任一环的入口点为第一公共点。

 

有可能两个链表均有环,但是它们并不相交。

 

算法:

找到两个链表的环入口。

如果有一个为NULL,一个非NULL,一定无交点,返回NULL。

如果均为NULL,变成两个无环链表求交点。

如果均非NULL,则是判断两个有环的链表是否有交点:

如果环入口相同,则它们实在分支上相交。

否则判断是否能从一个环中找到另一个的入口节点。

 

viewplain

1.// 通用的链表求第一公共交点的函数  

2.template  

3.ListNode* FindFirstCommonNode_2(ListNode* pHead1, ListNode* pHead2)  

4.{  

5.    ListNode* pEntrance1 = FindRingEntrance(pHead1);  

6.    ListNode* pEntrance2 = FindRingEntrance(pHead2);  

7.  

8.    ListNode* pResult = NULL;  

9.    if(pEntrance1 == pEntrance2)  

10.    {  

11.        ListNode* pTemp1 = NULL, *pTemp2 = NULL;  

12.        if(pEntrance1)  

13.        {  

14.            // 环入口点已经相交,寻找第一交点。

  

15.            pTemp1 = pEntrance1->pNext;  

16.            pTemp2 = pEntrance2->pNext;  

17.            pEntrance1->pNext = NULL;  

18.            pEntrance2->pNext = NULL;  

19.            pResul

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 工程科技 > 能源化工

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2