《算法设计手册》面试题解答 第二章:算法分析

简介:

  《算法设计手册》(The Algorithm Design Manual)课后面试题和解答。包括:未知大小的集合选取k个元素、数据备份方案、寻找数组最小数时赋值语句执行次数的期望、100层大楼抛大理石(抛灯泡)、电子秤找不足量金币、天平找重球、公司合并方案总数、海盗分赃等。

 

2-43.

  从n元集合中取一个k元子集,并要求每个元素概率相等。若n未知又该如何解决?

解答:

  原问题在http://www.cnblogs.com/wuyuegb2312/p/3141292.html#title3已经解答清楚了。

  此文也解决了从未知行数中等概率选择一行的方法,那么如果需要选择k个呢?为了简化起见,限定未知的n>=k。那么先选择前k个元素;对第k+1个元素,以概率k/(k+1)选择之,并以等概率1/k代替已选择的k个元素中的一个。

  这样,这一轮里前k个元素中某一个能留下的概率为1/(k+1) + [k/(k+1)] * [(k-1)/k] = k/(k+1)。那么对于第k+2个元素,类似地,以概率k/(k+2)选择之,并以等概率1/k代替已选择的k个元素中的一个,循环直至所有元素遍历结束。

  (解答启发自http://blog.csdn.net/fall221/article/details/8805733

 

2-44.

  有1000份各不相同的数据项和1000个存储数据的结点,每个结点可以存放3份不同的数据项。制定一个备份方案,使其在某些结点失效时损失最小。当任意3个结点失效时,丢失的数据的期望数值是多少?

解答:

  让所有结点存储内容不完全相同,是基本的。如果令结点n保存数据项n、n+1、n+2(取1000的模),最好情况是3个结点失效时不损失数据(各不连续或者2个连续),最坏情况是3个连续结点失效(n、n+1、n+2),损失n+2这一份数据。这个概率很容易计算,是1/10^(-6)。

  相关延伸阅读:

  RAID思想,保存异或结果,不过我算的概率相同:http://*.com/questions/10291690/1000-items-1000-nodes-3-items-per-node-best-replication-scheme-to-minimize-da

  类似的处理:http://blog.csdn.net/quietsound/article/details/9285375

 

2-45.

  从n+1个数中找出最小数时,min = A[i]语句执行次数的期望。其中数组下标A[0...n]。

  (首次赋值min=A[0]计算在内)

解答:

  首先想到的是逆序对。但是通过序列[1,3,2]和[1,2,3]可知,两者赋值次数是一样的,显然与逆序对无关。

  直接从期望入手,记E(n)为n+1个数时的该赋值语句期望执行次数。

  最小的数在末尾A[n]的概率为1/n,这时需要一次赋值。

  最小的数不在末尾A[n],则末尾处不需赋值,增加的赋值数为0。

  这样,有E(n) = E(n-1) +1/n且E(0)=0。其中E(n-1)已经包括最小的数在非A[n]处的所有情况。因此E(n)为

          《算法设计手册》面试题解答 第二章:算法分析

  n比较大时,约为lnn。

  (解答来自于:http://nbl.cewit.stony*.edu:60128/mediawiki/index.php/TADM2E_2.45

 

2-46.

  你有一栋100层高的大厦和2块大理石。你想找出一个最低楼层,从这个楼层开始,在它和比它更高的楼层上抛下大理石,落地会碎。如果有无限多块大理石,怎么最快找出这一层(抛的最少次数)?如果只有两块呢?(另一种说法:100层楼扔灯泡)

解答:

  无限多块时,很容易想到用折半查找来进行。但是如果使用最少的大理石块又该如何找呢?注意到如果某次抛下时大理石未碎,那么下次仍能够使用。为了只用两块大理石来判断楼层数,由于碎裂的最低楼层是一定的,先做分析:

  假设n是最多需要的测试次数(确定但未知,最坏情况),在第n层扔,如果碎了,由于只剩下一个灯泡,为了确定1至n-1层中哪一层,最坏情况是从1层一直扔到n-1层,共n-1次,加上之前的1次是n次,不超过n;如果未碎,那么上到2n-1层再扔,碎时同样有最坏情况从n+1层扔到2n-2层共n-2次,加上之前的是n次。依次类推,总结出每次测试都是n次,且确定的楼层范围是:n->2n-1->3n-2->...,即n + (n-1) + ... +1>100。求解使不等式成立的最小正整数是n=14。

  (解答来自于:http://*.com/questions/6547/two-marbles

 

2-47.

  有10袋金币,其中9袋中每个金币都是10克,另1袋中每个金币都是9克。给你一个能够数字显示重量的电子秤,找出全是9克的金币的那一袋。

解答:

  看到称重量可能会联想到用天平找几堆商品中不足量的一份。可是这里用的是能显示具体数值的电子秤哎!如果还用天平的思想,可太死板了。

  想想权重的概念,解法马上有了:从1号至10号袋中分别取1至10个金币,放到电子秤上。如果10袋全是10克的,那么应该显示550克;而缺几克,那就说明那个袋子里是9克的金币。一次解决,是不是很简单?

  当然,权重也可以用别的方案分配,不过上面是最简单的。

  (参考自:http://nbl.cewit.stony*.edu:60128/mediawiki/index.php/TADM2E_2.47

 

2-48.

  8个外表一样的球,其中7个等重,另1个比它们重。用天平在2次的比较后找出这个重球。

解答:

  由于有“2次比较”的提示,这个就简单了:把球分为(1,2,3),(4,5,6),(7,8)三组,第一次称(1,2,3)和(4,5,6),若一组重,那么将3个中取2个可得重的是这2个之一还是其余一个;否则将(7,8)称重。

  如果按这个思路,9个球也能够解决。

 

2-49.

  将n个公司合并成1个公司,一共有几种不同的方式合并?

解答:

  记合并方式f(n)种,f(n)=f(n-1)*g(n),其中g(n)是将n个公司通过一次合并变为n-1个公司的方法。显然g(n)为组合数C(n,2)。递推公式解得

  《算法设计手册》面试题解答 第二章:算法分析

  (参考自http://nbl.cewit.stony*.edu:60128/mediawiki/index.php/TADM2E_2.49

 

2-50.

  Rramanujan数是可以写作a^3+b^3=c^3+d^3的数,其中a!=c且b!=d,或者a!=d且b!=c。找出满足所有给定小于n的Rramanujan数。

解答:

  编程实现如下

《算法设计手册》面试题解答 第二章:算法分析
#include<stdio.h>
int main() {
    int n, i, count=0, j, k, int_count;
    printf("Enter the number of values needed: ");
    scanf("%d", &n);
    i = 1;
    while(count < n) {
       int_count = 0;
       for (j=1; j<=((int(pow(i, 1.0/3)); j++) {
          for(k=j+1; k<=((int(pow(i,1.0/3)); k++) {
              if(j*j*j+k*k*k == i)
              int_count++;
          }
       }
       if(int_count == 2) {
          count++;
          printf("\nGot %d Hardy-Ramanujan numbers %d", count, i);  
       }
       i++;
    }
}
《算法设计手册》面试题解答 第二章:算法分析

  注意几点以加速搜索:

  确保j<k,这样另一对j、k与原来的必然互不相等;

  两个for循环终止条件是j^3<i。

  (参考自:http://*.com/questions/11410798/finding-hardy-ramanujan-numbers

 

2-51.

  6个海盗分300美刀,分赃方法如下:有由资历最深的提出分配方案,进行投票。如果获得半数及以上支持,那么按照他的分配方案进行;否则,其他海盗杀掉他,资历第二深的海盗来提出分配方案,其后仍要投票表决,依次类推。请分析分配方法。(所有海盗都以自己存活为最优考虑,保证存活的条件下才尽可能希望多获得美刀。)

解答:

  将海盗按资历有深到浅编号为1,2,3,4,5,6。假设只剩下5,6两个海盗时,5无论提出怎样的分配方案,都能使支持过半(自己的一票),那么分配方法必然是:

  (5,6) ---->(300,0)

  时间倒流,加入海盗4。海盗4为了防止投票不过半而被杀死,需要拉拢海盗6。由于6在上一种情况里什么也分不到,这时只要4分给6,无论多少,6都会同意。这样,4给他最少的数目,即1。而5希望进入下一轮投票,因此只有给他全部300刀才能拉拢。由于投票已过半(2/3),不必拉拢5。此时分配方案为:

  (4,5,6) ---->(299,0,1)

  加入海盗3时,出于类似的考虑,提出这样的方案:

  (3,4,5,6) ---->(299,0,1,0),这样能拉拢5,不至于3死后,5什么也分不到。

  (299,1,0,0)必然不能拉拢4,因为将3干掉后4能获得299。至于为什么不用(299,0,0,1)这样的方案呢?此时6无论是否同意,他都有机会在本轮获得1美刀或者把3干掉后的下一轮必然获得1美刀。因此3的幸存与否是未知的,他不能做出这种使自己生命可能受到威胁的分配方式。后面的分析类似。有:

  (2,3,4,5,6) --->(298,0,1,0,1)

  (1,2,3,4,5,6) ----> (298,0,1,0,1,0)

  (参考自:http://nbl.cewit.stony*.edu:60128/mediawiki/index.php/TADM2E_2.51,这里我补充了不少分析。)

 

2.52.

  如果2.51中只有1美刀来分赃,谁会得到它,在这个分配过程中会死多少人?

解答:

  和上一题分析类似,当只有2个海盗时,年长那个一定能得到那1美刀;当海盗数大于等于3时,任何分配给自己的分配方案都不能保证自己一定能存活,不如直接分给倒数第二个海盗。(但即使如此,也可能被杀死。投票将演化成杀死一部分海盗,然后让倒数第二个海盗获得的过程。)

  (更一般的情况请参考http://en.wikipedia.org/wiki/Pirate_game。注意,中文wiki上没有详细的扩展情况的介绍。)

 








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

上一篇:DDD—Repository仓储&工厂模式


下一篇:DDD—聚合和聚合根