編程珠璣:用后綴數組尋找最長重復字符串


1.基本概念

子串:字符串 S 的子串 r[i..j] , i ≤ j ,表示 r 串中從 i 到 j 這一段,就是順次排列 r[i],r[i+1],...,r[j] 形成的字符串。

后綴:后綴是指從某個位置 i 開始到整個串末尾結束的一個特殊子串。字符串 r 的從 第 i 個字 符 開 始 的 后 綴 表 示 為 Suffix(i) ,也 就 是Suffix(i)=r[i..len(r)] 。

后綴數組:后綴數組 SA 是一個一維數組,它保存 1..n 的某個排列 SA[1] ,SA[2] , …… , SA[n] ,並且保證 Suffix(SA[i]) < Suffix(SA[i+1]) , 1 ≤ i<n 。也就是將 S 的 n 個后綴從小到大進行排序之后把排好序的后綴的開頭位置順次放入 SA 中。

 

 

2.問題描述

給定一個文本文件作為輸入,查找其中最長的重復子字符串。例如,"Ask not what your country can do for you, but what you can do for your
country"中最長的重復字符串是“can do for you”,第二長的是"your country"。

 

3.解決思路

利用后綴數組。首先輸入一個字符串到c[]中,例如“banana”,讀入時我們隊指針的數組a進行初始化,使得每個元素指向輸入字符串的相應字符,則元素a[0]指向整個字符串,下一個元素指向從第二個字符開始的數組后綴,等等。對於前面的輸入字符串,該數組能夠表示下面這些后綴:

a[0]:banana
a[1]:anana
a[2]:nana
a[3]:ana
a[4]:na
a[5]:a

如果某個長字符串在數組a中出現兩次,那么她將出現在兩個不同的后綴中,因此我們隊數組排序以尋找相同的后綴,下面將上面的數組a進行數組排序,結果如下

a[0]:a
a[1]:ana
a[2]:anana
a[3]:banana
a[4]:na
a[5]:nana

然后我們就可以掃描數組,通過比較相鄰元素來找出最長的重復字串,如上為"ana"

 

4.代碼實現

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXN 5000000
char c[MAXN], *a[MAXN];


int comlen(char *p, char *q)
{
    int i = 0;
    while(*p && (*p++ == *q++))
    {
             i++;
    }
    return i;
}

int pstrcmp(const void *a, const void *b)
{
    return  strcmp(*(char* const*)a, *(char* const*)b); //這里的 *(char* const*)a中的a 為指向指針的指針,
}                                                       //首先(char* const*)a 將變量a強制轉換成char類型的指向指針的const指針,
//然后用*進行 地址解引用
int main() { char ch; int i,n=0,maxlen=-1,maxi; while((ch = getchar()) != EOF && ch != '\n') { a[n] = &c[n]; c[n++] = ch; } c[n]='\0'; qsort(a, n , sizeof(char *), pstrcmp); for(i = 0;i < n-1; i++) { if(comlen(a[i], a[i+1]) > maxlen) { maxlen = comlen(a[i], a[i+1]); maxi = i; } } printf("%.*s\n", maxlen, a[maxi]); system("pause"); return 0; }


 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM