日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

后缀数组求最长重复子串

發(fā)布時(shí)間:2024/7/19 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 后缀数组求最长重复子串 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
問題描述
給定一個(gè)字符串,求出其最長重復(fù)子串
例如:abcdabcd
最長重復(fù)子串是 abcd,最長重復(fù)子串可以重疊
例如:abcdabcda,這時(shí)最長重復(fù)子串是 abcda,中間的 a 是被重疊的。

直觀的解法是,首先檢測長度為 n - 1 的字符串情況,如果不存在重復(fù)則檢測 n - 2, 一直遞減下去,直到 1 。
這種方法的時(shí)間復(fù)雜度是 O(N * N * N),其中包括三部分,長度緯度、根據(jù)長度檢測的字符串?dāng)?shù)目、字符串檢測。

改進(jìn)的方法是利用后綴數(shù)組
后綴數(shù)組是一種數(shù)據(jù)結(jié)構(gòu),對一個(gè)字符串生成相應(yīng)的后綴數(shù)組后,然后再排序,排完序依次檢測相鄰的兩個(gè)字符串的開頭公共部分。
這樣的時(shí)間復(fù)雜度為:生成后綴數(shù)組 O(N),排序 O(NlogN*N) 最后面的 N 是因?yàn)樽址容^也是 O(N)
依次檢測相鄰的兩個(gè)字符串 O(N * N),總的時(shí)間復(fù)雜度是 O(N^2*logN),優(yōu)于第一種方法的 O(N^3)


????? 對于類似從給定的文本中,查找其中最長的重復(fù)子字符串的問題,可以采用“后綴數(shù)組”來高效地完成此任務(wù)。后綴數(shù)組使用文本本身和n個(gè)附加指針(與文本數(shù)組相應(yīng)的指針數(shù)組)來表示輸入文本中的n個(gè)字符的每個(gè)子字符串。
??? 首先,如果輸入字符串存儲在c[0..n-1]中,那么就可以使用類似于下面的代碼比較每對子字符串:
int main(void) {int i , j , thislen , maxlen = -1;..................for(i = 0 ; i < n ; ++i ){for(j = i+1 ; j < n ; ++j ){if((thislen = comlen(&c[i] , &c[j])) > maxlen){maxlen = thislen;maxi = i;maxj = j;}}}..................return 0; }當(dāng)作為comlen函數(shù)參數(shù)的兩個(gè)字符串長度相等時(shí),該函數(shù)便返回這個(gè)長度值,從第一個(gè)字符開始:
int comlen( char *p, char *q ) {int i = 0;while( *p && (*p++ == *q++) )++i;return i; }??? 由于該算法查看所有的字符串對,所以它的時(shí)間和n的平方成正比。下面便是使用“后綴數(shù)組”的解決辦法。
??? 如果程序至多可以處理MAXN個(gè)字符,這些字符被存儲在數(shù)組c中:
#define MAXCHAR 5000 //最長處理5000個(gè)字符char c[MAXCHAR], *a[MAXCHAR];在讀取輸入時(shí),首先初始化a,這樣,每個(gè)元素就都指向輸入字符串中的相應(yīng)字符:
n = 0; while( (ch=getchar())!='\n' ) {a[n] = &c[n];c[n++] = ch; } c[n]='\0'; // 將數(shù)組c中的最后一個(gè)元素設(shè)為空字符,以終止所有字符串這樣,元素a[0]指向整個(gè)字符串,下一個(gè)元素指向以第二個(gè)字符開始的數(shù)組的后綴,等等。如若輸入字符串為"banana",該數(shù)組將表示這些后綴:
a[0]:banana
a[1]:anana
a[2]:nana
a[3]:ana
a[4]:na
a[5]:a
由于數(shù)組a中的指針分別指向字符串中的每個(gè)后綴,所以將數(shù)組a命名為"后綴數(shù)組"

第二、對后綴數(shù)組進(jìn)行快速排序,以將后綴相近的(變位詞)子串集中在一起
qsort(a, n, sizeof(char*), pstrcmp)后
a[0]:a
a[1]:ana
a[2]:anana
a[3]:banana
a[4]:na
a[5]:nana
第三、使用以下comlen函數(shù)對數(shù)組進(jìn)行掃描比較鄰接元素,以找出最長重復(fù)的字符串:
for(i = 0 ; i < n-1 ; ++i ) {temp=comlen( a[i], a[i+1] );if( temp>maxlen ){maxlen=temp;maxi=i;} } printf("%.*s\n",maxlen, a[maxi]);完整的實(shí)現(xiàn)代碼如下:
#include <iostream> using namespace std;#define MAXCHAR 5000 //最長處理5000個(gè)字符char c[MAXCHAR], *a[MAXCHAR];int comlen( char *p, char *q ) {int i = 0;while( *p && (*p++ == *q++) )++i;return i; }int pstrcmp( const void *p1, const void *p2 ) {return strcmp( *(char* const *)p1, *(char* const*)p2 ); }int main(void) {char ch;int n=0;int i, temp;int maxlen=0, maxi=0;printf("Please input your string:\n");n = 0;while( (ch=getchar())!='\n' ){a[n] = &c[n];c[n++] = ch;}c[n]='\0'; // 將數(shù)組c中的最后一個(gè)元素設(shè)為空字符,以終止所有字符串qsort( a, n, sizeof(char*), pstrcmp );for(i = 0 ; i < n-1 ; ++i ){temp=comlen( a[i], a[i+1] );if( temp>maxlen ){maxlen=temp;maxi=i;}}printf("%.*s\n",maxlen, a[maxi]);return 0; } 方法二:KMP
通過使用next數(shù)組的特性,同樣可以求最長重復(fù)子串,不過時(shí)間復(fù)雜度有點(diǎn)高挖。。

#include<iostream> using namespace std;const int MAX = 100000; int next[MAX]; char str[MAX];void GetNext(char *t) {int len = strlen(t);next[0] = -1;int i = 0 , j = -1;while(i < len){if(j == -1 || t[i] == t[j]){i++;j++;if(t[i] != t[j])next[i] = j;elsenext[i] = next[j];}elsej = next[j];} } int main(void) {int i , j , index , len;cout<<"Please input your string:"<<endl;cin>>str;char *s = str;len = 0;for(i = 0 ; *s != '\0' ; s++ , ++i){GetNext(s);for(j = 1 ; j <= strlen(s) ; ++j){if(next[j] > len){len = next[j];index = i + j; //index是第一個(gè)最長重復(fù)串在str中的位置 }}}if(len > 0){for(i = index - len ; i < index ; ++i)cout<<str[i];cout<<endl;}elsecout<<"none"<<endl;return 0; }
題目描述:求最長不重復(fù)子串,如abcdefgegcsgcasse,最長不重復(fù)子串為abcdefg,長度為7
#include <iostream> #include <list> using namespace std;//思路:用一個(gè)數(shù)組保存字符出現(xiàn)的次數(shù)。用i和j進(jìn)行遍歷整個(gè)字符串。 //當(dāng)某個(gè)字符沒有出現(xiàn)過,次數(shù)+1;出現(xiàn)字符已經(jīng)出現(xiàn)過,次數(shù)+1,找到這個(gè)字符前面出現(xiàn)的位置的下一個(gè)位置,設(shè)為i //并將之前的那些字符次數(shù)都-1。繼續(xù)遍歷,直到'\0' int find(char str[],char *output) {int i = 0 , j = 0;int cnt[26] = {0};int res = 0 , temp = 0;char *out = output;int final;while(str[j] != '\0'){if(cnt[str[j]-'a'] == 0){cnt[str[j]-'a']++;}else{cnt[str[j]-'a']++;while(str[i] != str[j]){ cnt[str[i]-'a']--;i++;}cnt[str[i]-'a']--;i++;} j++;temp = j-i;if(temp > res){res = temp;final = i;}}//結(jié)果保存在output里面for(i = 0 ; i < res ; ++i)*out++ = str[final++];*out = '\0';return res; } int main(void) {char a[] = "abcdefg";char b[100];int max = find(a,b);cout<<b<<endl;cout<<max<<endl;return 0; }




與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的后缀数组求最长重复子串的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。