《算法设计手册》面试题解答 第一章:算法设计简介

简介:

目录

 

系列简介:

  《算法设计手册》(The Algorithm Design Manual)是本比较经典的算法书了。如果说《算法导论》偏向于数学,那么《算法设计手册》更偏向于工程应用(至于《计算机程序设计艺术》,目前我是没时间通读,只是偶尔当工具书查查,就不提了)。前者的课后题中的面试题部分挺潮的,如果在google上搜索一下,发现很多都是名企考过的,或许是因为第二版出版时间比较近的缘故?我不大相信是作者自己出的然后被大公司拿去面试的,而是作者收录的考过的面试题。有了这一层筛选,这些面试题质量有保证啊。

  由于看的是英文版,大部分题都是我翻译过来的,个人英文水平有限,有的不好理解的地方尽量参照相关解答来理解,并咨询了在国外留学的朋友,可能仍有些措辞不准确或有误的地方,恳求谅解并欢迎提出。同时,有的题目用到的比较冷僻的知识可能会和正文有关系,这种情况会明确注明。

  虽然官方网站上有个wiki answer提供了大多数答案,不过有的不很合适,我写的和整理的都是比较好的解答。

  原作者的wiki answer页面http://www2.algorithm.cs.sunysb.edu:8080/mediawiki/index.php已经失效。

  另附上在线勘误表:http://www.cs.sunysb.edu/~skiena/algorist/book/errata

 

第1章:

1-28

  不用*和/计算整数除法。请找出最快的方式。

解答:

  虽然初始化一个计数变量,每当被除数减去除数的一次就自增一直到被除数小于除数这个暴力解法可行,但显然很慢。这是wiki answer答案,但它在很多情况下都不快,比如100/1。其执行的次数正好和相除的结果相同,用m表示除数,n表示被除数,时间复杂度是O(m/n)。

复制代码
// Note: This only works for positive values!
int divide(int numerator, int denominator) {
  int quotient = 0;

  while(numerator >= denominator) {
      numerator -= denominator;
      quotient++;
  }
  return quotient;
}
复制代码

   下面看看另一种解法。

  一般限制使用*和/时,很容易考虑使用位移运算来替代,因为对于无符号数,左移一位(在不溢出时)相当于乘以2,右移一位相当于除以2。如果在纸上进行除法的笔算,是只用到了乘法和减法的。但是一般的十进制整数除法和位运算有什么关系呢?为了将两者建立联系,必须把十进制数转化成二进制数,观察除法的进行情况来找规律。比如100/7,写成二进制来进行笔算,计算过程如下图:

  这样就简单了,从这个式子可以看出,二进制除法笔算只涉及了减法和隐含的移位与大小比较,原先的乘法已经被移位所代替。因此,具体的编码,就是把用笔算除法的过程转化成代码而已。

  不过,一般考虑使用除法的环境,必然要考虑除数是否为0。除数为0时这个除法是非法的,不能继续进行,需要报错。

  既然提到了编码,如果使用C语言来完成,要注意的是:在C标准中,带符号数右移的结果在C语言里是实现相关的,具体结果取决于实现,而不一定是用符号位补、用1补或者用0补最高位。为了避免这个陷阱,建议先确定结果——也就是商的符号,然后把被除数和除数都转化为无符号数,这样位移时就不会出错。

  但是,这又涉及了有带符号数与无符号数的转换,它们二者的表示范围的问题是不同的。好在被除数和除数从带符号数转化为无符号数时并不会丢失数据,而且商的绝对值必然小于被除数的绝对值(因为除数是整数,为0时报错,大于等于1时才继续进行),这时把商转化回带符号数时也不会丢失数据,可以放心的进行。不过这一点最好在面试时告诉面试官你已经注意到了这个问题,肯定会为你的印象加分。

 

复制代码
int division(int m,int n) {
    //calculate m/n without * and /
    unsigned int rest,divisor, op,result = 0;
    int flag;
    int bits = 0;
    //bits用于记录商的1在哪一位
    assert(n!=0);
    if((m<0 && n>0) || ( m>0 && n<0 ))
        flag = -1;
    else
        flag = 1;
    rest = m>0?m:-m;
    divisor = n>0?n:-n;
    if(rest < divisor)
        return 0;

    op = divisor;

    /*            2013.8.30           */
    /*经过博客园园友infinityu的提醒重写 */
    while(op<=rest) {
        bits++; 
        op=op<<1;
    }
    op=op>>1;
    bits--;

    while(op>=divisor) {
        if(rest>=op) {
            rest-=op;
            result += 1<<bits;
        }
        op = op>>1;
        bits--;
        
    }
    /*      重写部分结束         */

    return flag * result;
}
复制代码

 

 

 

  由于需要把被除数转化为二进制进行计算,最多做了其二进制表示位数次的减法,因此对于被除数m,算法复杂度为O(logm)。

  稍作修改,把最后的小于除数divisor的result取出就是余数,这样就能把除法运算改写为取模运算%了。如果把参数表修改为传递结果地址,同时获得商和余数也是可以的。

  可见,这一道面试题考到了算法优化、除法除数为0这个常见错误、将除法从十进制引申到二进制、二进制的位运算、语言特性中的无符号数和带符号数的位移、无符号数和带符号数的相互转换,你还可以更进一步探讨算法复杂度、以及算法的扩展性,确实很能考察被面试者对算法的掌握情况。

  p.s.经过园友infinityu的提示,发现源代码中有bug,重写之后已经对1~1000之间所有整数相互相除的测试。为了便于记录商的1应该在哪一位,使用变量bits来指示。

 

1-29:

  25匹马,一次最多5匹马比赛,如何用最少的比赛次数找到最快的前三匹马?(假设所有马的速度在每场比赛的发挥都一样且各匹马之间不相同,比赛时无法记录具体每匹马跑完全程的时间)

解答:

  老生常谈的问题,关键是找出每次的正确候选以及尽量利用上次比赛获得的信息

  先分5组A、B、C、D、E,组内比赛,假设A1为A组第一。一共5场。

  将A1~E1进行比赛,不妨设第一是A1,那么最快就是A1。

  第二快只能在A2、B1~E1中出现。同时,这时知道了B1~E1的速度,不妨B1>C1>D1>E1,这样D1、E1以及整个D组和E组可以被排除出第二和第三的候选。同时,C2必然不可能是第三快。这时候选为A2、A3、B1、B2、C1,比赛一次,前两名即为第二和第三。

  (注意:这里分析时没有"充分"利用所有已知信息。更进一步利用已知信息的方式请看扩展1。

  综上,一共比赛了7次。

 

扩展1:

  64匹马,每次最多8匹比赛,要求用最少场次获得前4名。其他条件同上题。

 解答:

  按照上题的分析方式并不能得到最少比赛次数,下面看看如何充分利用已知信息来达到最少比赛次数。

  首先分8组A~H决出各组顺序,共需8场,并且组内顺序排列为A1>A2>...>A8。

  第一名在A1~H1中决出,不妨设为A1>B1>...>H1,需要1场比赛。

  此时第二名只能是A2和B1其中之一(不同于上题分析,C1~H1其实可以直接抛弃),但决出第二名只用两个赛道太浪费了。为此进一步分析,如果A2>B1,那么第3名只能是A3、B1之一;如果B1>A2,那么第3名只能是A2、B2、C1。这两种情况都只涉及5匹马仍然不满8匹。用这种思路进行全面分析,表示为树状并把叶子处需要比较的马的编号进行标注:

  角逐第2名时A2>B1

    第3名候选A3,B1

    角逐第3名时A3>B1

      第4名候选A4,B1     ————(A2,A3,A4,B1)

    角逐第3名时A3<B1

      第4名候选A3,B2,C1    ————(A2,A3,B1,C1)

  角逐第2名时A2<B1

    第3名候选A2,B2,C1

    角逐第3名时A2>B2>C1

      第4名候选B2,A3     ————(A2,A3,B1,B2,C1)

    角逐第3名时A2>C1>B2

      第4名候选C1,A3     ————(A2,A3,B1,B2,C1)

    角逐第3名时B2>A2>C1

      第4名候选A2,B3     ————(A2,B1,B2,B3,C1)

    角逐第3名时B2>C1>A2

      第4名候选B3,C1     ————(A2,B1,B2,B3,C1)

    角逐第3名时C1>A2>B2

      第4名候选A2,C2,D1    ————(A2,B1,B2,C1,C2,D1)

    角逐第3名时C1>B2>A2

      第4名候选C2,B2,D1    ————(A2,B1,B2,C1,C2,D1)

  可见,如果能够一次比赛获得A2,A3,A4,B1,B2,B3,C1,C2,D1的完整排列次序才能知道前2~4名。很可惜一共是9匹马,不可能一场比赛必然获得结果。那么求最优方案,就是将以上各分支出现最晚出现的马去掉,即C2或D1,进行一场比赛。运气好的话这一轮可以决出前2~4,一共比赛10轮,运气不好的话还需要加赛一轮。而去掉C2或D1能够保证只比赛10轮的概率最大。

 

扩展2:

  25匹马,5个赛道,决出前5。

解答:

  分析和“扩展1”类似,留给读者自己完成。如果想校对答案,可以查阅:http://blog.csdn.net/hackbuteer1/article/details/7481342

 

=============================================================

  1-30~1.34是几个估算题,当年google确实考过其中的题目。不过这里不做解答了。

  关于估算题目的思路和解法,可以参考《编程珠玑》《编程珠玑(续)》和我写的相关文章:[珠玑之椟]估算的应用与Little定律

  另外,“不用再去算一辆校车上可以装多少个高尔夫球了。”因为 Google 已承认,那些用于测试求职者的智力题/脑筋急转弯(全世界有多少钢琴调音师?为什么井盖是圆的?),就无法预测出求职者是否会成为一位好员工。 “现在信赖更常规方法去面试潜在员工”。相关链接

1.30

  世界上有多少个钢琴调音师?

1.31

  美国有多少个加油站?

1.32

  曲棍球场上的雪有多重?

1.33

  美国公路一共有多长?

1.34

  平均来看,你翻开一本曼哈顿电话簿时,你需要随机翻开多少次才能找到一个给定的名字?





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

目录
相关文章
|
24天前
|
算法 Java 数据库
美团面试:百亿级分片,如何设计基因算法?
40岁老架构师尼恩分享分库分表的基因算法设计,涵盖分片键选择、水平拆分策略及基因法优化查询效率等内容,助力面试者应对大厂技术面试,提高架构设计能力。
美团面试:百亿级分片,如何设计基因算法?
|
29天前
|
算法 前端开发 Java
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题
这篇文章总结了单链表的常见面试题,并提供了详细的问题分析、思路分析以及Java代码实现,包括求单链表中有效节点的个数、查找单链表中的倒数第k个节点、单链表的反转以及从尾到头打印单链表等题目。
30 1
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题
|
18天前
|
机器学习/深度学习 算法 Java
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)
|
23天前
|
算法 Java 数据库
美团面试:百亿级分片,如何设计基因算法?
40岁老架构师尼恩在读者群中分享了关于分库分表的基因算法设计,旨在帮助大家应对一线互联网企业的面试题。文章详细介绍了分库分表的背景、分片键的设计目标和建议,以及基因法的具体应用和优缺点。通过系统化的梳理,帮助读者提升架构、设计和开发水平,顺利通过面试。
美团面试:百亿级分片,如何设计基因算法?
|
1月前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
59 2
|
2月前
|
算法 Java 数据安全/隐私保护
国密加密算法简介
国密指国家密码局认定的国产密码算法,主要包括SM1、SM2、SM3、SM4等,并持续完善。SM1是对称加密算法,加密强度与AES相当,需加密芯片支持;SM2是非对称加密,基于ECC算法,签名和密钥生成速度优于RSA;SM3为杂凑算法,安全性高于MD5;SM4为对称加密算法,用于无线局域网标准。本文提供使用Java和SpringBoot实现SM2和SM4加密的示例代码及依赖配置。更多国密算法标准可参考国家密码局官网。
156 1
|
1月前
|
存储 算法 安全
ArrayList简介及使用全方位手把手教学(带源码),用ArrayList实现洗牌算法,3个人轮流拿牌(带全部源码)
文章全面介绍了Java中ArrayList的使用方法,包括其构造方法、常见操作、遍历方式、扩容机制,并展示了如何使用ArrayList实现洗牌算法的实例。
14 0
|
2月前
|
机器学习/深度学习 JavaScript 算法
面试中的网红虚拟DOM,你知多少呢?深入解读diff算法
该文章深入探讨了虚拟DOM的概念及其diff算法,解释了虚拟DOM如何最小化实际DOM的更新,以此提升web应用的性能,并详细分析了diff算法的实现机制。
|
3月前
|
消息中间件 存储 算法
这些年背过的面试题——实战算法篇
本文是技术人面试系列实战算法篇,面试中关于实战算法都需要了解哪些内容?一文带你详细了解,欢迎收藏!
|
17天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。