KMP——字符串匹配

声明
本文主要是一些代码,加一些例题,基本为模板,仔细内容讲解会给出其他博主的链接

如果想要知道一个字符串是否在另一个字符串中出现过,那么首先想到的就是暴力枚举

#include
#include
#include
#include
#include
using namespace std;
string s1,s2;
int baolipipei() {
	int len1=s1.size() ;
	int len2=s2.size() ;
	int i=0,j=0;
	while(i>s1>>s2;
	cout<

但是,在两个字符串都很长的情况下,时间复杂度就很大,因此,给出一种算法KMP,可以解决字符串匹配等一类问题,在说KMP之前呢,首先说一下KMP用的一个数组,next数组(名字先不要在意)。next 数组各值的含义:代表当前字符之前的字符串中,有多大长度的相同前缀后缀。例如如果next [j] = k,代表j 之前的字符串中有最大长度为k 的相同前缀后缀。
那么如何求这个数组呢,暴力可以,但是复杂度过大
里面有详细的讲解,各位可以参考一下,主要还是理解之后大家记模板,也比较好记
https://blog.csdn.net/buppt/article/details/78531384
下面给出代码:

#include
#include
#include
#include
#include
using namespace std;
const int maxn=1005;
string s;
int next[maxn];//最长前后缀相等 
void GetNext() {
	int i,j=-1;
	next[0]=-1;//初始化为j=-1,next[0]=-1
	for(int i=1;i>s;
	GetNext();
	for(int i=0;i

现在呢开始进行匹配,我们知道,如果用暴力,当匹配到不正确的时候i会回到当前要查找的模式串(pattern)开头在对应的文本串(text)的位置下一位,那么根据next数组的含义,就可以直接回退到离当前j最近的j’使text[i] = pattern[j’+1] 能够成立。

这应该是博客上比较好的讲解kmp算法的了(可以看一看):
https://blog.csdn.net/v_july_v/article/details/7041827

KMP算法的一般思路:
① 初始化j=-1,表示pattern当前已被匹配的最后位。
②让i遍历文本串text,对每个i,执行③,④来试图匹配text[i]和pattern[j+1]。
③不断令j=next[j],直到j回退到-1,或者text[i] = pattern[j+1] 成立。
④如果text[i] = pattern[j+1] ,令j++。如果j达到pattern模式串的长度-1,说明pattern是text的子串。
代码如下:

#include
#include
#include
#include
using namespace std;
const int maxn=1005;
string s1,s2;
int next[maxn];
void GetNext() {//计算pattern的next数组
	int i,j=-1;
	next[0]=-1;
	for(int i=1;i>s1>>s2;
	if(KMP()) {
		cout<<"Yes\n";
	}
	else cout<<"No\n";
}

看到了求next数组和字符串匹配的代码后,发现他们惊人的相似,事实上:求解next数组的过程就是模式串自己匹配的过程。
接下来,怎么用KMP来统计子串出现的次数呢?
暴力的思路肯定还是回到开头,但是知道了上面的内容,我们回溯肯定就用next[j]了。
代码如下:

#include
#include
#include
#include
#include
using namespace std;
const int maxn=1005;
int next[maxn];
string s1,s2;
void GetNext() {
	int j=-1;
	next[0]=-1;
	for(int i=1;i>s1>>s2;
	cout<

next优化:
当next[j]表示的串的j+1位失配时,就要继续进行回退,那么如果还失配,同样的还要回退,我们最开始做next数组的意义不就是减少无用功吗?因此改变了一下next数组存放的内容,让失配时回退一次就行了。那么现在,我们把优化后的next数组几位nextvel数组,他失去了next数组的最长前后缀相等的含义,现可理解为当模式串pattern的i+1位失配时,i应该会退的最佳位置。
代码如下:

#include
#include
#include
#include
using namespace std;
const int maxn=1005;
string s;
int nextvel[maxn];//nextvel[i]的含义应理解为当模式串的i+1完全失配时,i应当退回的最佳位置 j
void GetNextvel() {
	int j=-1;
	nextvel[0]=-1;
	for(int i=1;i>s;
	for(int i=0;i

nextvel数组可以直接替换掉KMP中的next数组

直接套模板的几道题:
http://poj.org/problem?id=3461

#include
#include
#include
#include
#include
using namespace std;
const int maxn1=1e6+5;
const int maxn2=1e4+5;
char s2[maxn2],s1[maxn1];
int next[maxn2];
int len1,len2;

void GetNext() {
	int j=-1;
	next[0]=-1;
	for(int i=1;i

http://poj.org/problem?id=2752
这是直接利用next数组的题目,需要的就是最大前后缀,而next数组刚好有这个意思

#include
#include
#include
#include
#include
using namespace std;
const int maxn=400005;
int next[maxn];
int shu[maxn];
char s[maxn];
void GetNext(int len) {//求出每一位前缀后缀最大,用next记录 
	int j=-1;
	next[0]=-1;
	for(int i=1;i=0;i--){//反向输出 
			printf("%d",shu[i]);
			if(i) printf(" ");
		}
		printf("\n");
	}
	
}

http://caioj.cn/problem.php?id=1177

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int maxn=1005;
int nextvel[maxn];
string s1,s2;
int len1,len2;
void GetNextvel() {
	int j=-1;
	nextvel[0]=-1;
	for(int i=1;i>s1>>s2;
	len1=s1.size() ;
	len2=s2.size() ;
	KMP();
}

最后,其实我个人觉得一些算法模板直接记录下来,能够熟练的打下来也很厉害了(小声说)

你可能感兴趣的:(字符串】)