第二章提出了三个问题。
问题A:个定一个最多包含40个亿随机排列的32位整数的顺序文件,找出一个不在文件中的32位整数。在内存足够和只有几百个字节的内存的情况下,分别该如何解决这个问题。
问题B:将一个n元一维向量向左旋转(即循环移位)i个位置。例如,当n=8,且i=3时,向量abcdefgh旋转为defghabc。能否使用数十个额外字节的存储空间,在正比于n的时间内完成?
问题C:给定一个英语字典,找出其中的所有变位词集合。例如:“pots”、“stop”和“tops”互为变位词,即每一个单词都可以通过改变其他单词中字母的顺序来得到。
对于问题B,书中给了三种比较高效的解法。
解法一:“有点儿像精巧的杂技”,姑且称其为位移法。这个方法其实也是我们很容易的想到的方法:将x[0]移动到临时变量t,然后移动x[i]到x[0],x[2i]到x[i],依次类推,直到移动到n-i的位置为止,并将t的值赋值到x[n-i+1],这样我们完成了一趟赋值。然后,将x[1]移动到临时变量t,再按上述方法赋值。一共进行i趟,即得到旋转后的向量。
解法二:假定有一个函数可以将数组中特定部分的元素求逆。从ab开始,首先对a求逆,得到ar,然后对b求逆,得到a‘b’。最后整体求逆,得到(a‘b’)‘。此时就恰好是ba。于是就得到了用于旋转的代码。(a':表示对数组a求逆)
解法三:旋转向量其实就是交换现了ab的两段,得到ba。这里a代表x的前i个元素。假设a比b短,将b分为bl和br,使得br具有和a相同的长度。先交换a和br,得到brbla。在交换bl和br,即得到所求的向量。(这里书中说需要用递归解之,单个人感觉并无必要用递归,两次交换数据块即可。而且本人也不会在这个方法上使用递归,望网上的大神指点!!!)
以上三种方法需要的额外空间都是O(1),时间为O(n)。在文章后面有前两种方法的具体实现。
问题A和问题C用代码不易实现,理解其解题思路即可。
对于问题A:采用二分搜索技术。
问题C:可先将每个单词中的字母排序,再将排序后的相同的字母序列的单词进行归类,标识。
个人想法:
通过本章的学习,我们不仅要清晰地理解题意,还要根据题意在自己的大脑中搜索解决问题的方法,而这些方法往往是以往学习中用到过的。
下面是问题B的两种实现方法:
- #include <stdio.h>
- void reverse(int a[], int m, int n){ //To reverse the elements from m'th to n'th in array a.
- int temp;
- int i = 0;
- for(i=0; i<=(n-m)/2; i++){
- temp = a[m+i];
- a[m+i] = a[n-i];
- a[n-i] = temp;
- }
- }
- void vectorRotate1(int a[], int m, int n){ //通过求逆
- reverse(a, 0, m-1 );
- reverse(a, m, n-1);
- reverse(a, 0, n-1);
- }
- int gcd(int m, int n){//求最大公约数
- if(n<m){
- return gcd(n, m);
- }
- else if((n%m) == 0){
- return m;
- }
- else{
- return gcd(n%m, m);
- }
- }
- void vectorRotate2(int a[], int m, int n){//这是书本上的做法,求m和n的最大公约数,
- int temp;
- int i, j;
- int p = gcd(m, n);
- for(i=0; i<p; i++){
- temp = a[i];
- j = i+m;
- while((j%n)!=i){
- a[(j-m+n)%n] = a[j];
- j += m;
- }
- a[j-m] = temp;
- }
- }
- int main(){
- int a[] = {1,2,3,4,5,6,7,8,9,10};
- int i=0;
- for(i=0; i<10; i++){
- printf("%d ", a[i]);
- }
- printf("\n");
- vectorRotate1(a, 3, 10);
- for(i=0; i<10; i++){
- printf("%d ", a[i]);
- }
- printf("\n");
- vectorRotate2(a, 2, 10);
- for(i=0; i<10; i++){
- printf("%d ", a[i]);
- }
- printf("\n");
- int b[2][2] = {{1, 1}};
- for(i=0;i<2;i++){
- for(int j=0; j<2; j++){
- printf("%d\n", b[i][j]);
- }
- }
- return 0;
- }