link:
問題:比如 weksabcdjklabcdll 最長重複字串為"abcd"
解析:字尾陣列舉例
如下目標字串: bananas 其長度為7,則字尾陣列的長度為7,分別是以b開頭的字串(長度為7),以a開頭的字串(長度為6),以n開頭的字串(長度為5)。。。最後乙個是以s開頭的字串(長度為1)。
字尾[0] bananas
字尾[1] ananas
字尾[2] nanas
字尾[3] anas
字尾[4] nas
字尾[5] as
字尾[6] s
回到正題,查詢一段文字中最長的重複字串。(注意:這不同於演算法設計課中常講的兩個字串的最長公共子串行問題(lcs),lcs問題的最長公共字串可以不是連續的)
最樸素的演算法是,讓字尾陣列之間兩兩比較,找出最長的公共字串(注意,這裡的最長的公共字串必須是以首字元參與匹配的,如果首字母都不匹配,那麼長度為0,eg字尾[0]和字尾[1]之間的首字母不匹配,則兩者的最長公共字串長度為0.。),但是時間複雜度為o(n^2).
該思想基於以下兩個資訊:
1)如果存在乙個最長的重複字串,那麼兩個字串均是來自文字串不同的字尾,但這兩個字尾有相同的字首!(這個字首也就是重複字串了)
2)既然最終結果的字尾肯定擁有相同的字首,那麼我就沒有必要讓全部字尾之間兩兩比較,而僅僅比較具有相同的字首(首字母)的字尾即可!這可以大大的減少比較的次數,提高效率。
所以,演算法的流程是,先將字尾陣列字母排序(其實就是對字元陣列排序),然後順次比較(避免了兩兩比較)即可。
字尾[0] ananas
字尾[1] anas
字尾[2] as
字尾[3] bananas
字尾[4] nanas
字尾[5] nas
字尾[6] s
字尾[2]和字尾[3]不用比較(a!=b) ……
字尾[5]和字尾[6]不用比較(n!=s)
so,最終的比較結果是 字尾[1]和字尾[2] 之間存在最長公共字串"ana"在字尾[0]裡。
#include
#include
//qsort
#include <
string
.h>
#define maxchar 1000 /
/最長處理1000個字元
char c[maxchar]
,*a[maxchar]
;int comlen( char *p, char *q )
int pstrcmp(
const void *p1,
const void *p2 )/*
** find longest repeat string
by suffix array
*"weksabcdjklabcdgg" 最長重複字串為"abcd"*/
char * lrs_sufarr(
)c[n]='
\0';
/* 列印字尾陣列,不是必須的。*
/for
(i = 0; i < n;
++i)
printf(
"%d: %s\n"
, i+1, a[i]);
qsort( a, n, sizeof(char*
), pstrcmp );/
/qsort後,n個字尾陣列[i.
.n-1]就是排好序的了.
printf(
"------ after sort------\n");
for(i = 0; i < n;
++i)
printf(
"%d: %s\n"
, i, a[i]);
//在字尾陣列中,找出最長重複字首的,即是最長重複子串
for(i=0; i < n-1;
++i )}}
//printf(
"\nselect first %d from:%s\n"
, maxlen, a[maxi]);
*(a[maxi]
+ maxlen)='
\0';
printf(
"max repeat str: %s\nwith length of %d.\n"
, a[maxi]
, maxlen)
;return a[maxi];}
字尾陣列的應用:
上面的**新增乙個height陣列,
temp = comlen( a[i], a[i+1] ); 寫成
height[i] = comlen( a[i], a[i+1] ); //0<=i最長公共字首
給定乙個字串,詢問某兩個字尾的最長公共字首。
直接套用,ret = min(height[i]) k字尾樹里有重要意義。
例 2 :可重疊最長重複子串
給定乙個字串,求最長重複子串,這兩個子串可以重疊。
// ret = max(height[i]) 0<=i
例 3 :最長回文子串
將整個字串反過來寫在原字串後面,中間用乙個特殊的字元隔開。這樣就把問題變為了
求這個新的字串的某兩個字尾的最長公共字首。
eg:abcbaebf ----> abcbaebf#fbeabcba
最長重複子串(字尾陣列)
時間限制 1000 ms 記憶體限制 3000 kb 描述 對於乙個字串s1,其中s2是他的乙個子串 長度嚴格小於s1長度 如果s2在s1 現次數超過1次,那麼s2就是乙個重複子串,現在的要求是給定s1,請求出他的最長重複子串 如果有多個長度一樣的最長子串,請輸入字典序最小那個串 比如bbbaaac...
最長重複子串 可重複 字尾陣列
時間限制 1000 ms 記憶體限制 3000 kb 描述 對於乙個字串s1,其中s2是他的乙個子串 長度嚴格小於s1長度 如果s2在s1中出現次數超過1次,那麼s2就是乙個重複子串,現在的要求是給定s1,請求出他的最長重複子串 如果有多個長度一樣的最長子串,請輸入字典序最小那個串 比如bbbaaa...
字尾陣列求最長重複子串
於 問題描述 給定乙個字串,求出其最長重複子串 例如 abcdabcd 最長重複子串是 abcd,最長重複子串可以重疊 例如 abcdabcda,這時最長重複子串是 abcda,中間的 a 是被重疊的。直觀的解法是,首先檢測長度為 n 1 的字串情況,如果不存在重複則檢測 n 2,一直遞減下去,直到...