《算法设计手册》面试题解答 第三章:数据结构

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介:

3-18.

  你查字典时用的是什么方法?

解析:

  既然要和算法相关,除了随机尝试,明显应该用二分查找。

  不要嫌它简单,其实这是道MS和Google用过的面试题。

 

3-19.

  假设你有一个装满T恤衫的衣柜,如何组织这些T恤衫以便以后取衣服?

解析:

  由于衣柜是线性存储,肯定要用到排序从而应用二分查找。具体到T恤衫,可以按颜色排序。

  当然,如果这是个商场中的衣柜,那么还应该在同样式内部按尺码排序。

 

3-20.

  写一个函数,找出单链表的中间结点。

解析:

  比较常见,最简单的解法是用两个指针,一个每次后移1个,另一个每次后移2个,速度快的达到末尾时,慢的正好在中间。实际编写的时候注意边界条件(最好把NULL做第0个结点,考虑结点数奇偶性不要把快的指针移动出界),略。

 

3-21.

  写一个函数判断两个二叉树是否全等。树全等包括结构相同和对应结点数据相同。

解析:

  二叉树遍历的变形,只是写函数返回值时可能迷惑。可以这样写:

复制代码
int compare(struct node* a, struct node* b) {

  // 1. both empty -> true
  if (a==NULL && b==NULL) return(true);   

// 2. both non-empty -> compare them
  else if (a!=NULL && b!=NULL) {
    return(
      a->data == b->data &&
      compare(a->left, b->left) &&
      compare(a->right, b->right)
    );
  }

  // 3. one empty, one not -> false
  else return 0;
}  
复制代码

 

3-22.

  写一个把二叉搜索树转化为链表的程序。

解析:

  如果允许使用额外的辅助数据结构,可以遍历树时构造链表,也可以遍历树时把结点压入队列最后出队构造。

  如果不允许使用额外的存储空间,把二叉搜索树原地转化为双链表,思想还是树的递归遍历:把根的左子树和右子树分别转化为双链表,再与根相连接。只不过连接时右子树,要注意是把原先的根作为双链表末尾来连接。下面贴的代码来自于何海涛《剑指Offer》面试题27:二叉搜索树与双向链表:

void ConvertNode(BinaryTreeNode* pNode, BinaryTreeNode** pLastNodeInList);

BinaryTreeNode* Convert(BinaryTreeNode* pRootOfTree)
{
    BinaryTreeNode *pLastNodeInList = NULL;
    ConvertNode(pRootOfTree, &pLastNodeInList);

    // pLastNodeInList指向双向链表的尾结点,
    // 我们需要返回头结点
    BinaryTreeNode *pHeadOfList = pLastNodeInList;
    while(pHeadOfList != NULL && pHeadOfList->m_pLeft != NULL)
        pHeadOfList = pHeadOfList->m_pLeft;

    return pHeadOfList;
}

void ConvertNode(BinaryTreeNode* pNode, BinaryTreeNode** pLastNodeInList)
{
    if(pNode == NULL)
        return;

    BinaryTreeNode *pCurrent = pNode;

    if (pCurrent->m_pLeft != NULL)
        ConvertNode(pCurrent->m_pLeft, pLastNodeInList);

    pCurrent->m_pLeft = *pLastNodeInList; 
    if(*pLastNodeInList != NULL)
        (*pLastNodeInList)->m_pRight = pCurrent;

    *pLastNodeInList = pCurrent;

    if (pCurrent->m_pRight != NULL)
        ConvertNode(pCurrent->m_pRight, pLastNodeInList);
}
ConvertBinarySearchTree

  既然来自于《剑指Offer》,这里也附注下好了,设计的测试用例为:

  • 功能测试:完全二叉树、所有节点都没有左/右子树、只有一个结点的二叉树。
  • 特殊输入测试:指向根节点指针为NULL。

 

3-23.

  写一个逆置链表的函数。再写一个非递归实现。

解析:

  递归实现只要将当前结点作为已处理部分的最后一个结点附加上去即可。

//http://nbl.cewit.stonybrook.edu:60128/mediawiki/index.php/TADM2E_3.23
Node* Reverse(Node*head)
{
   Node* temp=NULL;
   if(head==NULL)
   {
       return NULL;
   }
   if(head->next==NULL)
       return head;
   temp=Reverse(head->next);
   head->next->next=head;
   head->next=NULL;
   return temp;
}
递归实现

  非递归实现需要保存当前操纵结点的下一个结点以免断链,一次遍历即可。下面的代码来自于何海涛《剑指Offer》面试题16:反转链表:

ListNode* ReverseList(ListNode* pHead)
{
    ListNode* pReversedHead = NULL;
    ListNode* pNode = pHead;
    ListNode* pPrev = NULL;
    while(pNode != NULL)
    {
        ListNode* pNext = pNode->m_pNext;

        if(pNext == NULL)
            pReversedHead = pNode;

        pNode->m_pNext = pPrev;

        pPrev = pNode;
        pNode = pNext;
    }

    return pReversedHead;
}
非递归实现

  测试用例:

  • 链表头指针是NULL。
  • 输入链表只有一个头结点。
  • 输入链表有多个结点。

 

3-24.

  为网页爬虫设计一个数据结构,来判断URL是否被访问过。要求时间空间都最优。

解析:

  我一开始想到的是URL分段进行hash,有人说用前缀树完成匹配http://nbl.cewit.stonybrook.edu:60128/mediawiki/index.php/TADM2E_3.24提到使用布隆过滤器。简单了解下吧,看上去和分段hash的思路很类似。

布隆过滤器的原理是,当一个元素被加入集合时,通过K个Hash函数将这个元素映射成一个位阵列(Bit array)中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检索元素一定不在;如果都是1,则被检索元素很可能在。这就是布隆过滤器的基本思想。

优点

相比于其它的数据结构,布隆过滤器在空间和时间方面都有巨大的优势。布隆过滤器存储空间和插入/查询时间都是常数(O(k))。另外, Hash函数相互之间没有关系,方便由硬件并行实现。布隆过滤器不需要存储元素本身,在某些对保密要求非常严格的场合有优势。

布隆过滤器可以表示全集,其它任何数据结构都不能;

km相同,使用同一组Hash函数的两个布隆过滤器的交并差运算可以使用位操作进行。

缺点

但是布隆过滤器的缺点和优点一样明显。误算率是其中之一。随着存入的元素数量增加,误算率随之增加。但是如果元素数量太少,则使用散列表足矣。

另外,一般情况下不能从布隆过滤器中删除元素. 我们很容易想到把位列阵变成整数数组,每插入一个元素相应的计数器加1, 这样删除元素时将计数器减掉就可以了。然而要保证安全地删除元素并非如此简单。首先我们必须保证删除的元素的确在布隆过滤器里面. 这一点单凭这个过滤器是无法保证的。另外计数器回绕也会造成问题。

在降低误算率方面,有不少工作,使得出现了很多布隆过滤器的变种。

 

3.25

  给定一个字符串和一本杂志,需要你从杂志上剪下来字母从而拼成这个字符串。给出高效率的算法来判断这本杂志是否能拼成这个字符串。

解析:

  对杂志逐个字母进行统计,当种类和个数都达到给定字符串中对应字母的个数时结束,否则判断不能拼成。即将字符串按字母序hash,其值是在字符串的出现次数;检索杂志时,每个字母与hash表进行判断。如果值非0,则减1。

  为加速确定是否结束,还可以存储字符串内各不相同的字母数,每当hash表中某项由1变0,则计数减1,减到0时表示可以拼成。遍历结束时计数仍为正数则表示不能拼成。

 

3.26

  翻转句子。"My name is Chris" 变成"Chris is name My"。要求最优化时间和空间复杂度。

解析:

  常见的序列旋转问题。可以参考:http://www.cnblogs.com/wuyuegb2312/p/3139925.html#title013

 

3.27

  判断一个链表是否有环,并找出环的入口。要求不使用额外存储空间。

解析:

  链表找环问题。解法和原理请见:http://www.cnblogs.com/wuyuegb2312/p/3183214.html

 

3.28

  给定一个n元数组X,求出n元数组M,满足M[i] = X[1]*X[2]* ... *X[i-1]*X[i+1]*...*X[n]。不允许用除法,可以用额外的存储空间。(提示:可以快于O(n^2))

解析:

  很常见的题目,《编程之美》2.13"子数组最大乘积"利用到了这个算法。

  求M[i]需要左右两段X[1...i-1]和X[i+1...n]的积,那么分别构造数组保存即可。即L[i] = X[1]*X[2]* ... *X[i],R[i] = X[i]*...*X[n]。

  构造L时从1开始构造,总时间O(n);R从n开始倒序构造,同样是O(n)。构造X[i]只需L[i-1]和R[i+1]的乘积即可(为便于计算令L[0]=R[n+1]=1),也只需O(n)。算法整体复杂度是O(n)。

 

3.29

  写出算法来获取一个页面上出现频率最高的英文词组(仅限两个单词组成的词组,如New York)。使用什么数据结构?要求时间和空间最优。

解析:

  在《程序设计实践》(Practise of Programming)上有一段二元马尔科夫链文本生成器做了类似的工作:读入所有词对构成哈希表。解决这个问题也是一样:从头至尾读入每个词对(一次后移一个单词)并放入hash表,记录词对出现的次数,然后求得值最大的词对。








本文转自五岳博客园博客,原文链接:http://www.cnblogs.com/wuyuegb2312/p/3260011.html,如需转载请自行联系原作者

目录
相关文章
|
2月前
|
机器学习/深度学习 算法 数据挖掘
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
162 4
|
3月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
112 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
12天前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
37 2
|
28天前
|
存储 运维 监控
探索局域网电脑监控软件:Python算法与数据结构的巧妙结合
在数字化时代,局域网电脑监控软件成为企业管理和IT运维的重要工具,确保数据安全和网络稳定。本文探讨其背后的关键技术——Python中的算法与数据结构,如字典用于高效存储设备信息,以及数据收集、异常检测和聚合算法提升监控效率。通过Python代码示例,展示了如何实现基本监控功能,帮助读者理解其工作原理并激发技术兴趣。
57 20
|
2月前
|
数据采集 存储 算法
Python 中的数据结构和算法优化策略
Python中的数据结构和算法如何进行优化?
|
2月前
|
算法
数据结构之路由表查找算法(深度优先搜索和宽度优先搜索)
在网络通信中,路由表用于指导数据包的传输路径。本文介绍了两种常用的路由表查找算法——深度优先算法(DFS)和宽度优先算法(BFS)。DFS使用栈实现,适合路径问题;BFS使用队列,保证找到最短路径。两者均能有效查找路由信息,但适用场景不同,需根据具体需求选择。文中还提供了这两种算法的核心代码及测试结果,验证了算法的有效性。
131 23
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
82 1
|
3月前
|
算法 Java 数据库
美团面试:百亿级分片,如何设计基因算法?
40岁老架构师尼恩分享分库分表的基因算法设计,涵盖分片键选择、水平拆分策略及基因法优化查询效率等内容,助力面试者应对大厂技术面试,提高架构设计能力。
美团面试:百亿级分片,如何设计基因算法?
|
3月前
|
机器学习/深度学习 存储 缓存
数据结构与算法学习十:排序算法介绍、时间频度、时间复杂度、常用时间复杂度介绍
文章主要介绍了排序算法的分类、时间复杂度的概念和计算方法,以及常见的时间复杂度级别,并简单提及了空间复杂度。
61 1
数据结构与算法学习十:排序算法介绍、时间频度、时间复杂度、常用时间复杂度介绍
|
3月前
|
算法 前端开发 Java
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题
这篇文章总结了单链表的常见面试题,并提供了详细的问题分析、思路分析以及Java代码实现,包括求单链表中有效节点的个数、查找单链表中的倒数第k个节点、单链表的反转以及从尾到头打印单链表等题目。
46 1
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题

热门文章

最新文章