问题一
给定一个最多包含40亿个随机排列的32位整数的顺序文件,找出一个不在文件中的32位整数(在文件中至少缺失一个这样的数——为什么?)。
在具有足够内存的情况下,如何解决该问题?如果有几个外部的“临时”文件可用,但是仅有几百字节的内存,又该如何解决该问题?
二分搜索案例
假定一个数万行的输入文件中,包含一个错误行。
- 若每次只排查几行数据 可能要排查几千次
- 若使用二分搜索排查,最多十几次即可找到问题
解决思路
文件包含最多40亿个随机排列的32位整数,而我们需要找出一个不存在于该文件中的32位整数。(至少缺少一个整数,因为一共有2^32也就是4 294 967 296个这样的整数。)
如果有足够的内存,可以采用第1章中介绍的位图技术,使用536 870 912个8位字节形成位图来表示已看到的整数。然而,该问题还问到在仅有几百个字节内存和几个稀疏顺序文件的情况下如何找到缺失的整数?
我们采用已知包含至少一个缺失元素的一系列整数作为范围,并使用包含所有这些整数在内的文件表示这个范围。灵机一动的结果是通过统计中间点之上和之下的元素来探测范围:或者上面或者下面的范围具有至多全部范围的一半元素。由于整个范围中有一个缺失元素,因此我们所需的那一半范围中必然也包含缺失的元素。
问题二
将一个n元一维向量向左旋转i个位置。例如,当n=8且i=3时,向量abcdefgh旋转为defghabc。
简单的代码使用一个n元的中间向量在n步内完成该工作。你能否仅使用数十个额外字节的存储空间,在正比于n的时间内完成向量的旋转?
解决思路
将整个向量看作由ab两段组成,问题转化为将ab转换成ba。
参考下图的翻手例子(a=12345,b=678910)
可以得到如下程序
reverse(0,i-1) /* cbadefgh */
reverse(i,n-1) /* cbahgfed */
reverse(0,n-1) /* defghabc */
问题三
给定一个英语字典,找出其中的所有变位词集合。例如,“pots”、“stop”和“tops”互为变位词,因为每一个单词都可以通过改变其他单词中字母的顺序来得到
低效复杂的思路
考虑单词中所有字母的排列,即全排列
考虑单词duodenocholecystostomy有22!种排列,少量的乘法运算表明22! ≈1.124 × 10^21。即使假设以闪电一样的速度每百亿分之一秒执行一种排列,这也要消耗1.1 × 10^9秒
解决思路 排序
可通过排序单词内的所有字母,实现同为变位词的统一标识 即pans、snap都可计算出标识anps
变位词程序可如下图所示
- sign程序,计算出每个单词对应的标识
- srot程序,按照标识排序
- squash程序,同一标识下的所有单词压缩为一行