编程珠玑(2)第二章学习笔记

第二章提出了三个问题。

        

        问题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的两种实现方法:

         

[cpp]  view plain copy
  1. #include <stdio.h>  
  2.   
  3.   
  4. void reverse(int a[], int m, int n){ //To reverse the elements from m'th to n'th in array a.  
  5.   
  6.     int temp;  
  7.     int i = 0;  
  8.   
  9.     for(i=0; i<=(n-m)/2; i++){  
  10.         temp = a[m+i];  
  11.         a[m+i] = a[n-i];  
  12.         a[n-i] = temp;  
  13.     }  
  14. }  
  15. void vectorRotate1(int a[], int m, int n){ //通过求逆  
  16.   
  17.     reverse(a, 0, m-1 );  
  18.     reverse(a, m, n-1);  
  19.     reverse(a, 0, n-1);  
  20. }  
  21.   
  22. int gcd(int m, int n){//求最大公约数  
  23.   
  24.     if(n<m){  
  25.         return gcd(n, m);  
  26.     }  
  27.     else if((n%m) == 0){  
  28.         return m;  
  29.     }  
  30.     else{  
  31.         return gcd(n%m, m);  
  32.     }  
  33. }  
  34. void vectorRotate2(int a[], int m, int n){//这是书本上的做法,求m和n的最大公约数,  
  35.   
  36.     int temp;  
  37.     int i, j;  
  38.     int p = gcd(m, n);  
  39.   
  40.     for(i=0; i<p; i++){  
  41.         temp = a[i];  
  42.         j = i+m;  
  43.         while((j%n)!=i){  
  44.             a[(j-m+n)%n] = a[j];  
  45.             j += m;  
  46.         }  
  47.         a[j-m] = temp;  
  48.     }  
  49. }  
  50.   
  51.   
  52. int main(){  
  53.   
  54.     int a[] = {1,2,3,4,5,6,7,8,9,10};  
  55.     int i=0;  
  56.   
  57.     for(i=0; i<10; i++){  
  58.         printf("%d  ", a[i]);  
  59.     }  
  60.     printf("\n");  
  61.   
  62.     vectorRotate1(a, 3, 10);  
  63.   
  64.     for(i=0; i<10; i++){  
  65.         printf("%d  ", a[i]);  
  66.     }  
  67.     printf("\n");  
  68.       
  69.     vectorRotate2(a, 2, 10);  
  70.   
  71.     for(i=0; i<10; i++){  
  72.         printf("%d  ", a[i]);  
  73.     }  
  74.     printf("\n");  
  75.   
  76.     int b[2][2] = {{1, 1}};  
  77.   
  78.     for(i=0;i<2;i++){  
  79.         for(int j=0; j<2; j++){  
  80.             printf("%d\n", b[i][j]);  
  81.         }  
  82.     }  
  83.   
  84.     return 0;  
  85. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值