您的位置:首页 > 编程语言

编程珠玑 第二章 算法

2010-04-19 19:09 471 查看
本章一开始提出了三个问题:

A、给定一个最多包含40亿个随机排列的32为整数的顺序文件,找出一个不存在文件中的32位整数(在文件中至少缺失一个这样的数——为什么?)。在具有足够内存的情况下,如何解决该问题?如何有几个外部的“临时”文件可用,但是仅有几百字节的内存,又该如何解决问题?

问题解析:

该问题包含三个子问题。

1.在文件中至少缺失一个这样的数?为什么呢?这是因为32为表示能表示232-1个数,这个数>4*10的九次方=40亿大的数,因此肯定在文件中缺失一个这样的数。

2.在具有足够内存的情况下如何解决这个问题?根据前一篇介绍的位向量表示法,可以判断该数是否存在。不过要一次性将所有数都映射到内存中,大约所需要40 0000 0000/8Byte=500MB的内存。

3.如何有几个外部的“临时”文件可用,但是仅有几百字节的内存,该问题有该如何解决呢?书中建议使用二分搜索技术。普通的二分搜索技术在建立有序序列上的。如何建立搜索条件呢?必须定义一个范围、在这范围内表示元素的方式以及用来确定哪一半范围存在缺失整数的探测方法。(书中写的还没搞明白!!)

B.将一个n元一维向量向左旋转i个位置。例如,当n=8且i=3时,向量abcdefgh旋转为defghabc。简单的代码使用一个n元的中间向量在n步内完成该工作。你能否仅适用数十位额外字节的存储空间,在正比于n的时间内完成向量的旋转?

问题很明确,向量左旋。在没有看他的分析之前,做了以下思考:

1.最简单的做法是做i次的向量的左旋1次的运算,最后得到向量左旋i个位置。代码很简单。这里就不贴出了。没有借助外存,但是时间复杂度高O(in);

2.借助外存,先将前i个元素存储起来,后将向量从i位置开始移位,最后将外存存贮的那部分向量加到尾部。借助外存,时间复杂o(n+i).

书中给出两种巧妙的解法,一种是杂技式,一种是逆式。这里主要是说明逆式。假设旋转向量分为两部分ab,要得到ba。首先对a求逆,得到arb,后对b求逆,得到arbr。然后再对整个结果求逆得到(arbr)r,即ba。

代码:
void reverseWord(char* word,int b,int e)
{
if (b>=e)
{
return;
}
for (int i =0;i<=(e-b)/2;i++)
{
char c =word[b+i];
word[b+i] = word[e-i];
word[e-i] =c;
}
}

//逆式
void Reverse2(char * word,int i,int n)
{
reverseWord(word,0,i-1);
reverseWord(word,i,n-1);
reverseWord(word,0,n-1);
}


算法复杂是O(n),并没有借助外存。思想很巧妙。
C、给定一个英语字典,找出其中的所有变位词的集合。例如,"pots","stop"和"tops"互为变位词,因为每一个单词都可以通过改变其他单词中字母的顺序来得到。

我的想法是对每次单词的副本按照字母表的顺序排序,然后再按照副本进行聚类。即相同的副本聚在一起,当然变相也是排序。
书中提到的是先一中方式排序(水平翻手),再用另一种排序方式排序(垂直翻手)。意思差不多。
后记:
本章习题较难,现正在努力研究中。书的前言中提到:阅读本书的一个提示:不要读得太快。要仔细阅读,一次读一章。要尝试解答书中提到的问题——有些问题需要集中精力思考一两个小时才会变得容易。然后,要努力解答每章末尾的习题:当读者写下答案时,从本书学到的大部分知识就会跃然纸上。才是真正的懂得!
书到用时方恨少!努力!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: