KMP例題

KMP算法:實現兩個字符串的匹配。
KMP講解

//KMP模板
#include<bits/stdc++.h>
using namespace std;

void get_next(string t, int* next){
	int i=0;
	int j=-1;
	next[0]=-1;
	while(i<t.length()){
		if(j==-1||t[i]==t[j]){
			i++,j++;
			next[i]=j;
		}
		else{
			j=next[j];
		}
	}
}

int kmp(string s, string t){
	int next[t.length()+5];
	get_next(t, next);
	int i=0;
	int j=0;
	while(i<s.length()&&j<t.length()){
		if(j==0||s[i]==t[j]){
			i++,j++;
		}
		else{
			j=next[j];
		}
	}
	
	if(i==s.length()){
		return -1;
	} 
	if(j==t.length()){
		return i-t.length()+1;
	}
}

int main(){
	string a, b;
	a="abcde";
	b="cd";
	cout<<kmp(a, b);
	
	return 0;
} 

推薦學習KMP鏈接

例一:子串

牛客題目鏈接
給出一個正整數n,我們把1…n在k進制下的表示連起來記爲s(n,k),例如s(16,16)=123456789ABCDEF10, s(5,2)=11011100101。現在對於給定的n和字符串t,我們想知道是否存在一個k(2 ≤ k ≤ 16),使得t是s(n,k)的子串。
輸入描述:
第一行一個整數n(1 ≤ n ≤ 50,000)。
第二行一個字符串t(長度 ≤ 1,000,000)
輸出描述:
“yes"表示存在滿足條件的k,否則輸出"no”
示例1
輸入
8
01112
輸出
yes


這道題直接套KMP模板就行,沒有太多拐彎抹角的東西。

#include<bits/stdc++.h>
using namespace std;
char jz[18]="0123456789ABCDEF";
string t, s="";

void zh(int n, int k){
	string ss;
	while(n>0){
		if(n%k!=0){
			ss+=jz[n%k];
		}
		else ss+=jz[0];
		n/=k;
	}
	reverse(ss.begin(), ss.end());
	s += ss;
}

void get_next(string t, int*next){
	int i=0;
	int j=-1;
	next[0]=-1;
	while(i<=t.length()){
		if(t[i]==t[j]||j==-1){
			j++, i++;
			next[i]=j;
		}
		else{
			j=next[j];
		}
	}
}

bool kmp(string s, string t){
	int next[t.length()+5];
	get_next(t, next);
	int i=0;
	int j=0;
	while(j<t.length() && i<s.length()){
		if(t[j]==s[i]||j==0){
			j++, i++;
		}
		else{
			j = next[j];
		}
	}
	if(j==t.length()){
		return true;
	}
	return false;
}

int main()
{
	int N;
	cin>>N>>t;

	for(int k=2; k<=16; k++){
		s="";
		for(int n=1; n<=N; n++){
			zh(n, k);
		}
//		cout<<s<<endl;
		if(kmp(s, t)){
			cout<<"yes";
			return 0;
		}
	}
	cout<<"no";
	
	return 0;
} 

例一:Youhane Assembler

牛客題目鏈接
題意:輸入多個字符串,挑選兩個字符串s1,s2。
判斷s1的後綴字母與s2的前綴字母有多少個字符能匹配。
eg:s1=“ABCDE” s2=“CDEFG”
ps:它們能匹配的字符有3個爲"CDE"。
eg: s1=“CDEFG” s2=“ABCDE”
ps:它們能匹配的字符有0個,因爲s2字符串中沒有G。


運用KMP特性

在KMP裏我們瞭解到,next數組能夠將一個字符串前後綴進行匹配,從而達到避免字符串匹配的時候重複判斷的效果。
在題目中,我們可以利用next數組匹配字符串前後綴的功能來實現s1與s2的匹配。

解題分析

①、將s1與s2結合爲一個字符串s
s=s2+"#"+s1
(ps:s2要前綴,s1要後綴,在中間加上"#"防止s2與s1“越界匹配”)
②、判斷字符串s的前綴與後綴有ans個字符能匹配成功。
ans = next[s.length()]

#include<bits/stdc++.h>
using namespace std;
string str[300005];
void get_next(string s, int * next){
	int i=0;
	int j=-1;
	next[0]=-1;
	while(i<s.length()){
		if(s[i]==s[j]||j==-1){
			i++, j++;
			next[i]=j;
		}
		else{
			j = next[j];
		}
	}
}

int main()
{
	int n;
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n;
	for(int i=1; i<=n; i++)
		cin>>str[i];
	int m;
	cin>>m;
	for(int i=1; i<=m; i++){
		int q1, q2;
		cin>>q1>>q2;
		string s = str[q2]+"#"+str[q1];
		int len=s.length();
		if(q1==q2){
			cout<<str[q1].length()<<endl;
		}
		else{
			int next[s.length()+5];
			get_next(s, next);
			cout<<next[len]<<endl;
		}
	}
	return 0;
}

現在初次接觸這種題型,往後遇到KMP題型會陸續添上。

希望將自己的學習經驗分享給有需要的人。
我是小鄭,一個不怎麼會的小白

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