1.基本概念數組
子串:字符串 S 的子串 r[i..j] , i ≤ j ,表示 r 串中從 i 到 j 這一段,就是順次排列 r[i],r[i+1],...,r[j] 造成的字符串。spa
後綴:後綴是指從某個位置 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 中。code
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.解決思路get
利用後綴數組。首先輸入一個字符串到c[]中,例如「banana」,讀入時咱們隊指針的數組a進行初始化,使得每一個元素指向輸入字符串的相應字符,則元素a[0]指向整個字符串,下一個元素指向從第二個字符開始的數組後綴,等等。對於前面的輸入字符串,該數組可以表示下面這些後綴:string
a[0]:banana
a[1]:anana
a[2]:nana
a[3]:ana
a[4]:na
a[5]:aio
若是某個長字符串在數組a中出現兩次,那麼她將出如今兩個不一樣的後綴中,所以咱們隊數組排序以尋找相同的後綴,下面將上面的數組a進行數組排序,結果以下class
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; }