題目列表:
Poj1226 http://poj.org/problem?id=1226
Poj1961 http://poj.org/problem?id=1961
Poj2185 http://poj.org/problem?id=2185
Poj2406 http://poj.org/problem?id=2406
Poj2541 http://poj.org/problem?id=2541
Poj2752 http://poj.org/problem?id=2752
Poj3080 http://poj.org/problem?id=3080
Poj3167 http://poj.org/problem?id=3167
Poj3450 http://poj.org/problem?id=3450
Poj3461 http://poj.org/problem?id=3461
這裏轉有一篇介紹KMP算法的比較好的文章:
http://blog.csdn.net/dooder_daodao/article/details/6299504
下面就各題進行分析:
1226 求最長公共子串,並且這個公共子串可以是某個字符串反串的子串,可以找最小的一個字符串,
然後枚舉其所有的子串,並在其它串中查找,查找時用KMP或者strstr函數;
1961 這題考察對next數組的理解 next數組中的j本質上維護了從距離i最近的上一個重複串中與i對應的位置
因此如果i % (i - j) == 0 && i / (i - j ) > 1則這個剛好掃描到了重複的串
2185 這題就不多說了,各種錯誤的代碼都AC了,不過相較而言,Discuss裏 Iamjw 講了一段比較好:
比如:2 8
aaabcaaa
abababab
這個思路會給出16吧?但是答案是12。
因爲橫排的計算出錯了~其實是因爲第一個串符合題意的長度不止5,還有6,7,8。所以事實上應該把每個串符合
題意的長度都記錄下來,然後選一個公共最小的。比如第一個串是 5,6,7,8第二個串是2,4,6,8所以橫排應該選6。
這裏只需解決兩個問題:
1) 如何找到串s的所有符合題意的長度? 只需要對s進行一次kmp特徵值計算,如果發
現後面有多餘的後綴,就把後綴再拿來做一次kmp,不斷重複,直到沒有後綴。這個過程就可以記錄所有符合題
意的串了。
比如aaabcaaa,先求一遍kmp,得到5,再對後綴aaa求一遍,得到1(即6,7,8)。
又比如aabaabaabaa,先求一遍kmp,得到3(即3,6,9),再對後綴aa求一遍,得到1,(即10,11)。
2)
如何找到所有串公共的最短符合題意的長度? 直接用(列數)c個桶來統計一下就行了~ 如果某個長度出現了(行數)r次,
那麼它就是公共的。最後從小到大遍歷一遍就求出了最小長度。
2406 還是next數組的性質,if(len%(len-next[len])==0),則重複子串的長度爲
len-next[len].
2541 這一題可直接用KMP來做的,反方向取後十三個字符做爲模式串,向前進行匹配
2752 同 2406
3080 枚舉子串,逐個匹配。
3167 比較不同的一個KMP題目,而且比較好的一個題,參照了下面這篇博客,講的很細緻:
同樣對模式串求next數組,並據next進行匹配,不同處在於使用了不同的比較方式。
http://www.cppblog.com/zxb/archive/2010/10/06/128782.aspx?opt=admin
3450 同3080,甚至就修改幾行代碼
3461 最顯而易見的KMP題目,下面給出此題的代碼:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 10008
#define M 1000008
char s[M];
char t[N];
int nxt[N];
void GetNext(char *t,int lt)
{
int i,j;
nxt[0]=-1;
for(i=0,j=-1;i<lt;i++){
while(j!=-1&&t[i]!=t[j])
j=nxt[j];
nxt[i+1]=++j;
}
}
int KMP(char *s,int ls,char *t,int lt)
{
int i,j,r=0;
for(i=j=0;i<ls;i++){
while(j!=-1&&s[i]!=t[j])
j=nxt[j];
if(++j==lt) r++;
}
return r;
}
int main()
{
int T;
int lt;
scanf("%d",&T);
while(T--){
scanf("%s%s",t,s);
GetNext(t,lt=strlen(t));
printf("%d\n",KMP(s,strlen(s),t,lt));
}
return 0;
}