菜狗的KMP學習

菜dog的日常生活發表於2024-03-26

為什麼我們要學習KMP呢?這就不得不說起當年暑假在校隊集訓的時候,苦逼做不出題目的痛苦時光了。

三個人看著題目中字串匹配的那個環節,思索了整整三個小時。

不得不說,從0到1,遠比在前人的肩膀上前行要難得多。真不知的這些變態大佬是怎麼想出來的。

先來提及一下,當時我們用人腦想出來的程式碼(我沒有說他們不是人:對於大部分人來說,那肯定就是一個個照著去比對就行了,然而很遺憾的是:

可惜時間太短,我無法愛上你——超時......

這就是那所謂的BP演算法

1.樸素模式匹配(BP)

由於這個真的太基礎,懶得廢話了。就是應該去主串和模式串一個個去配對,如果該字元匹配,則j++,否則j=0,然後i++

int index_BP(string s,string p){
	int sl=s.length(),pl=p.length();
	for(int i=0;i<=sl-pl;i++){
		int flag=1;
		for(int j=0;j<pl;j++){
			if(s[i+j]=!p[j]){
				flag=0;
				break;
			}
		}
		if(flag)
		return i;
	}
	return -1;
}

2.KMP演算法(三個人名...)

(1)字首與字尾

什麼是字首和字尾捏?

ju個栗子,比如說有個字串“abac”,那麼對於該字串而言,“a”,“ab”,“aba”則是它的字首(PS:嚴格來講,“abac”和空串也可以算作字首)。

相應的,對於字尾而言就是,“c”,“ac”,“bac”等。

(2)next陣列

這個時候,可能就會想前字尾和字串的匹配有什麼關係呢?其實,重點就在於資訊的重複利用。

比如說,對於模式串“abdad”而言,如果在第5個字元“d”的時候不匹配,那麼我們不需要再次去重頭可以匹配,因為對於字串“abda”而言,有相同的前字尾“a”。

所以我們只需要從“b”開始進行相應的配對即可。

從這裡就可以看出,KMP演算法實質就是利用當前字元前的字元子串的相同前字尾,來跳過大量沒有意義的重複匹配。

這個是相關的動畫。。。有點醜,而且有點慢,但是,菜狗的我不會調速度

接下來就是求next陣列了,next陣列是利用模式串得到的。

那為什麼要叫做next陣列呢?那是因為如果當前字元不匹配,下一個要比對的模式串的字元是哪個。

菜狗的KMP學習

相應的計算公式如上所示。

(3)相關的程式碼

int mynext[200000];
void get_next(string s){
	int l=s.size(),k=-1;
	mynext[0]=-1;
	for(int i=1;i<=l;){
		if(k==-1||s[i]==s[k]){
			i++;k++;
			mynext[i]=k;
		}
		else k=mynext[k];
	}
}
int index_kmp(string s,string p,int pos){
	int i=pos,j=0;
	int sl=s.size(),pl=p.size();
	for(i=pos,j=0;i<sl&&j<pl;){
		if(j==-1||s[i]==p[j]){
			i++;j++;
		}
		else j=mynext[j];
	}
	if(j>=pl) return i-pl;
	else return -1;
}

3.相關例題

P3375 【模板】KMP - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

Password - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

相關文章