算法題2

  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';
    }
}
函數調用時的第一個參數是第一個元素的地址
當然可以採用
定義二維動態數組來避免上面的問題

發佈了51 篇原創文章 · 獲贊 18 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章