KMP算法的C++实现及解释(简洁,通俗易懂)
最近在回顾字符串的匹配相关算法,把之前的思路又理了理。
问题描述
有两个字符串str1和str2,我们想知道str2是否在str1中。计算机实现这个有很多算法,比如BF算法(暴力匹配算法,时间复杂度是O(n* m)),RK算法(BF算法的升级版,利用了哈希算法,对主串中的n-m+1个子串分别求哈希值,然后逐个与模式串的哈希值比较大小,时间复杂度是O(n))。此外还有BM算法,他是一种非常高效的字符串匹配算法,有实验统计它的性能是著名的KMP算法的3到4倍,BM算法利用坏字符规则和好后缀规则,在模式串和主串匹配的过程中当模式串和主串某个字符不匹配的时候能够跳过一些肯定不会匹配的情况,将模式串往后多滑动几位。
重点回顾KMP算法,代码及思路整理如下:
KMP算法同BM算法一样也是希望找到某一种规律,使得在匹配时能够跳过一些肯定不会匹配的情况,将模式串往后多滑动几位。
//str1为主串,str2为模式串,在str1中检查是否包含str2,存在则返回起始位置,不存在则返回-1
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void getnext(const string &str2,vector<int> next)
{ next.clear();
next.resize(str2.size());
if (str2.length()== 1)
{
next[0]=-1;
return ;
}
next[0]=-1;
next[1]=0;
int len= str2.length();
int i=2,cn=0;//cn为最长前缀的后一个字符
while(i<len)
{
if (str2[i-1]==str2[cn]) //如果前一个字符和cn对应的值相等
next[i++]=++cn;//如果相等则此处的值为,cn+1
else if (cn>0)
cn=next[cn];//不等的话继续往前推
else
next[i++] =0;//不等的话并未没法往前推就变为0
}
}
int kmp( const string &str1, const string &str2,vector<int> & next)
{
int i1 = 0, i2 = 0;
while (i1<str1.length() && i2<str2.length())
{
if (str1[i1]==str2[i2])//两者比对,相等则主串和模式串都加加
{
i1++;
i2++;
}
else if (next[i2]==-1)//两者没有匹配则进一步判断i2是否还有回退的资格,如果等于-1说明已经退到头了,则只能i1++;
{
i1++;
}
else//还可以退,则i2回到到next数组指定的位置再进行比对
i2=next[i2];
}
return i2 == str2.length()?i1-i2:-1;
//如果str2已经扫描完了说明已经找到了,返回str1中找到的起始位置;如果没有扫描完说明没有找到返回-1;
}
int main()
{
string str1,str2;
cin>>str1>>str2;
vector<int> next;
int k;
k=kmp(str1,str2,next);
return k;
}