编程珠玑学习笔记三 第二章总结

第二章开头提出了三个非常好的问题:

1.给定一个最多包含40亿个随机排列的32位整数的顺序文件,找出一个不在文件中的32位整数。

在内存足够的情况下,可以用位图来解决这个问题,位图中标记为0对应的数就是所要找的。

当内存不足时,此时采用分治的思想:

        按最高位(也可按低位)的值对所有整数分类,高位为0的一组,记为A,高位为1的一组,记为

        B,分别统计A,B组元素的个数。此时若len(A)<2^31,则A组中必有漏掉的数(此时缺失的

        数高位一定为0);同理可判断B中是否有遗漏。选择一个有遗漏的分组,再对它的次高位进行分类,

        一直递归下去直到对最低位也进行了分类。此时缺失的数每一位的值均可以确定,找出了这个数。

2.将一个n元一维向量旋转i个位置。

书中给出了两个算法:

  (1)杂技法。该方法很巧妙,但不太容易理解,不知道算法的作者是怎么想出来的。

  (2)分块求逆。这个算法很好用,通过分别求逆后再求逆来得到最终的结果。

         比如要将n元向量旋转i位,过程为:

          reverse(0,i-1)

          reverse(i,n-1)

          reverse(0,n-1)

我的思路:可以用空间换时间的思想来解决。比如要旋转的n元向量为abcdefgh,要将它

旋转3位:defghabc

我们可以开辟一块新空间来再存储一份n元向量,将它们拼接,为abcdefghabcdefgh,则

所要求的旋转结果为这个字符串的子串,取s[3:len(n)+3)即为所求

3.给定一个英文字典,找出变位词的集合。

解决思路就是对每一个单词进行标记,使得互为变位词的单词有相同的标记,而不是变位词的单词

有不同的标记。

这里列出几种可用的标记方法:

 (1)对每个单词进行字典序排序,则互为变位词的单词有着相同的排序(若单词量大,对每个单词排序比较耗时)

 (2)将26个英文字母分别对应一个素数,则一个单词的标记为组成它的每个字母的素数乘积。这样保证了

        变位词的标记时一样的,而非变位词有不同的标记。

        但当一个单词长度比较长时,计算一个乘积结果,数据量也比较大。

 (3)统计一个单词中各字母出现的次数,并以此作为标记索引。如mississippi对应i4m1p2s4,可以将1省略,为

       i4mp2s4.

第二章的思考题总结:

1.没有时间进行预处理,则直接按该单词的标识值去查字典,标识相同的单词输出

  如有时间和空间进行预处理,可以先对整个字典进行标识计算,将计算值作为索引hash到不同的数组中,并将标识相同

  的单词(变位词)链在同一个链表中。

  查找时按给定的单词去查索引表(第一个节点即为链表表头节点),然后一次取出变位词输出。

2.给定包含43亿个32位整数的顺序文件,如何找出一个出现至少两次的整数?

 思路:32位整数大约有42亿多个整数,文件包含43亿个整数,则必定有重复。

 若内存空间足够,可以用位图来解决。当一个数对应的位置已经为1,则它是重复的数字。

 也可像第二章开头的问题一中的二分法思想来解决。

6.同变位词的思路

7.将4000*4000的矩阵转置。

书中给出的解决方案是对每个元素插入行号,列号,根据转置矩阵的特点,对原来的矩阵先按列排序,

再按行排序,得到结果矩阵。

8.给定一个n元实数集合,一个实数t和一个整数k,如何快速确定是否存在一个k元子集,其元素之和不超过t?

思路:如果能得到n元集合最小的k个实数,计算它们的和,若是小于t,则这k个数即为所求;若大于t,则不存在

        这样的k元子集。

        问题转化为求n元实数集合中k个最小元素的问题,也就是topk问题。很自然得想到用堆来解决:用集合中的前

        n个元素构建一个大顶堆,将剩下的n-k个元素分别于堆顶元素比较大小,若小于堆顶,则用它替换堆顶元素,重新

       调整成堆;若大于堆顶元素,则舍去。最后存在于堆中的k个元素即为所要求的最小的k个数。

9.假设进行了k次查找,则顺序查找时间为nk,二分查找时间为nlgn(排序时间)+xlogn(查找时间)

  使得 nk>nlgn+xlogn

posted on 2012-08-01 11:34  温柔的暴力  阅读(1757)  评论(0编辑  收藏  举报

导航