算法题2

来源:互联网 发布:淘宝手机详情图片尺寸 编辑:程序博客网 时间:2024/05/22 14:19
  1.下面将要介绍一个高效的数据结构,并将它应用在一个很小的问题上:给定一个输入文件,查找其中最长的重复子字符串。例如,“Ask not what your country can do for you, but what you can do for your country”中最长的重复字符串就是“can do for you”,“your country”是第二个位置。如何编写解决这个问题的程序?
我们的程序至多可以处理MAXN个字符,这些字符被存储在数组c中:
#define MAXN 5000000
char c[MAXN], *a[MAXN];
我们将使用一个简单的数据结构“后缀数组”;虽然是从1990年才提出这个术语,但至少在1970年就开始使用这个结构。这个结构是从一个指向字符的指针数组a。当我们读取输入时,首先初始化a,这样,每个元素就都指向输入字符串中的相应字符:
       while ( ch = getchar() ) != EOF)
              a[n] = &c[n]
              c[n++] = ch
       c[n] = 0
数组c中的最后一个元素是一个空字符,它终止了所有字符串。
       元素a[0]指向整个字符串,下一个元素指向以第二个字符开始的数组的后缀,等等。在输入字符串“banana”后,该数组表示这些后缀:
       a[0]: banana
       a[1]: anana
       a[2]: nana
       a[3]: ana
       a[4]: na
       a[5]: a
       由于数组a中的指针分别指向字符串中的每个后缀,所以将数组a命名为“后缀数组”。
       如果在数组c中两次出现长字符串,它就有两个不同的后缀,因此,我们将排序数组找到相同的后缀。“banana”数组排序成:
       a[0]: a
a[1]: ana
a[2]: anana
a[3]: banana
       a[4]: na
       a[5]: nana
       然后就可以扫描该数组临接元素,以找出最长重复的字符串,本例中为“ana”
       我们使用qsort函数排序后缀数组:
       qsort(a, n ,sizeof(char*), pstrcmp)
比较函数pstrcmp将一个间接层添加到库函数strcmp中,这个对数组的扫描使用comlen函数统计两个邻接单词中相同的字符数:
       for i = [0, n)
              if comlen(a[i], a[i+1] ) > maxlen
                     maxlen = comlen(a[i], a[i+1])
                     maxi = i
       printf(“%.*s/n”, maxlen, a[maxi]);
printf语句使用“*”精确地输出字符串的maxlen字符。
      
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
 
int pstrcmp(char **p, char **q)
{   return strcmp(*p, *q); }
 
int comlen(char *p, char *q)
{     int i = 0;
       while (*p && (*p++ == *q++))
              i++;
       return i;
}
 
#define M 1
#define MAXN 5000000
char c[MAXN], *a[MAXN];
 
int main()
{   int i, ch, n = 0, maxi, maxlen = -1;
    while ((ch = getchar()) != EOF) {
        a[n] = &c[n];
        c[n++] = ch;
    }
    c[n] = 0;
    qsort(a, n, sizeof(char *), pstrcmp);
    for (i = 0; i < n-M; i++)
        if (comlen(a[i], a[i+M]) > maxlen) {
            maxlen = comlen(a[i], a[i+M]);
            maxi = i;
        }
    printf("%.*s/n", maxlen, a[maxi]);
    return 0;
}

 该算法的复杂度为O(n log n)

2.输入是一个N×N的数字矩阵并且已经读入内存。每一行均从左到右增加。每一列则从上到下增加。给出一个O(N)最坏情形算法以确定数X是否在矩阵中。

k是被寻找的数,   i,x是横坐标,j,y是纵坐标。
1.   如果k> m[i][j]=>   对于所有的元素m[x][y]此时   x> =i,   y> =j
2.   如果k=m[i][j]找到
3.   如果k <m[i][j]=>   k大于   所有的元素   m[x][y]   此时   x <=i,   y <=j

因此只需要构造一种搜索的方法(用图形比较好理解,不过这儿没法贴图):
1.   首先从i=0,   j=0开始搜索j,得到最右端的第一个大于k的j,这儿记为jMax。此时可以推出:如果k存在,那么k所在的元素m[x][y]必定有x> =i,   y <=jMax-1,也就是说必定在(i,jMax)的左下方。
2.   然后从i=0,j=jMax-1开始:
3.   如果k> m[i][j],则++i               因为此时   x <=i   y <=j的元素均小于k,所以可以往下走
4.   如果k <m[i][j],则--j                 因此此时x> =i   y> =j的元素均大于k,所以只能往左走,往上走不行,因为上面的数肯定都是大于或者小于k的
5.   第3,4步不断重复直到找不到或者找到为止

时间复杂度O(2N)
程序代码如下:

bool search(int *array, int l, int r, int num)
{
    int i=0;
   int j=0;
   for(;j<r;++j)
   {
       if(array[i*r + j]>num)
            break;
      else if(array[i*r + j] == num)
           return true;
    }

    --j;
    while(1)
   {
          if(array[i*r + j]>num) //左走
              j--;
          else if(array[i*r + j] < num) )//下走
             i++;
          else
              return true;
          if(i>=l || j<0)  //找不到
              return false;
 }
 return false;
}
调用的search(&m[0][0],N,N,num)
对于二维数组:
(1)两个维数都不给出,把两个维数都作为形参:
         void func(double a[][], int dim1,int dim2);
(2)直接将数组名作为指向指针的指针:
         void func(double **a, int dim1,int dim2);
这都是错误的。因为,参数声明a[][]本身就是非法的。因为,为了确定元素的位置,多维数组的第二个以后的维都必须知道。一种正确的解决方法是:
void print(int *a, int dim1, int dim2)
{
    for(int i=0; i<dim1; i++){
        for(int j=0; j<dim2; j++)
           cout<<a[i*dim2+j]<<'/t';
        cout<<'/n';
    }
}
函数调用时的第一个参数是第一个元素的地址
当然可以采用
定义二维动态数组来避免上面的问题

原创粉丝点击