关于字符串匹配问题——KMP算法
(第一次做哪里不好请见谅哈~)
kmp算法: (kmp算法)
由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。
KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。
时间复杂度O(m+n)。
1.next数组:
代码:
int get_next(int next[],string s)
{
int i=-1,j=0;
next[j]=i;
while(j<s.length())
{
if(i==-1||s[i]==s[j])
{
i++;
j++;
next[j]=i;
}
else
i=next[i];
}
}
以 “abcaba“ 为 想要查找到的字符串 为例
-
首先,把第一位的next存成0, next[0]=-1;
-
每一位的next都是前面字符串(不包括全部)的最长的前缀与后缀字符串相等的数;
以“abcaba“ 为例:
字符串的第二个字母b 前面的字符串为 “a”,所以为0;
字符串的第三个字母c 前面的字符串为 “ab”,前缀为 a ,后缀为 b,所以为0;
。。。。。。
字符串的第六个字母a 前面的字符串为 “abcab”,
前缀为:“a”,“ab”,“abc”,“abca”;
后缀为:“b”,“ab”,“cab”,“bcab”,所以最大相等的字符串为“ab”,所以为2。
2.字符串匹配
以“ababcaba”
“abcaba” 为例;
3.
因为a——c 不匹配所以下面的字符串回缩到next[2]的位置(next[2]=0,s[0]=a)。
4.
再次匹配。
依次匹配后,最终成功,并输出第一次匹配的第一个字母的位置。(若没有匹配到字符串,则输出无字符串匹配)
3.全部代码:
#include<iostream>
#include<cstring>
using nameapace std;
const int Size = 100;
int get_next(int next[],string s)//获得next数组
{
int i=-1,j=0;
next[j]=i;
while(j<s.length())
{
if(i==-1||s[i]==s[j])
{
i++;
j++;
next[j]=i;
}
else
i=next[i];
}
}
void KMP(string p,string s,int next[])
{
int i,j,q=s.length();
i=0;j=0;
while(i<p.length()&&j<q)
{
if(p[i]==s[j]||j==-1)
{
i++;
j++;
}
else
j=next[j];
}
if(j==p)
cout<<"从第"<<i-q+1<<"个字母开始匹配"<<endl;
else
cout<<"无字符串匹配!"<<endl;
}
int main()
{
int next[Size];
string p,s;//p为较长的字符串,s为想要查找到的字符串。
cin>>p>>s;
get_next(next,s);
KMP(p,s,next);
return 0;
}
若想观察,长的字符串中能查找出多少个想要查找的字符串,可以将KMP代码重把长的字符串都遍历一遍,出现匹配成功,即用 count++即可。