Poj KMP 總結

 題目列表:

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;
}


 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章