1.字符串蛮力匹配算法
主串长度是 n
模式串长度为 m
则最大匹配次数是 O(n-m+1),;例如,匹配到主串最后四位就不再匹配了,
#include <iostream>
#include <string> //string要小写,不是大写
using namespace std;
bool strnor();
bool strnor(string T,string S)
{
int j=0,k=0;
for (int i = 0; i <=T.length()-S.length(); i++)
{
if (T[i]==S[0])
{
k=i;
k+=1;
for(int j=1;j<S.length();j++)
{
if (T[k]==S[j])
{
if (T[k]==S[j] && j==S.length()-1)
return true;
k+=1;
continue;
}
else
{ break; }
}
}
}
return false;
}
int main()
{
string T,S;//T是主串,S是模式串
cin>>T;
cin>>S;//这样的读入是他不会识别,遇见空格 就会自动划分
cout<<strnor(T,S);
system("pause");
return 0;
}
最好情况是O(m),即是开始就匹配完成
字符串暴力匹配代码:(非以下,留着以后写)
2.KMP算法
这里非常重要的一点是:
① 如果模式串是诸如ABCDEFGH……这样的,没有重复的字母或者汉字,那么KMP算法和暴力匹配算法一样
② 当然,一般不可能出无重复的,模式串一般都会有重复的,那么在手工计算中只需要考虑模式串而无需在意主串
PS:这里说一下,为什么next数组和字符串编号从1开始,天勤的老师是这么说的,因为大部分学校考题喜欢从1开始,所以我们一般只需要考虑从1开始的,就是那么无奈😂🤣
2.1 next[]数组手算过程
例如:模式串:ababaaababaa的计算结果为
最长的前后缀
计算方式:初始化,next的数组的next[0]=0,next[1]=1, 也有的next[0=-1,next[1]=0,他们之前并无公共部分,这点直接写上去
1.从i=2开始计算,扫描到i位置时,计算[ 0…x], [y…i-1]的最大长度size,当然x≤i-1,
要求是str[0…x]=str[y…i-1],x可以等于y2.那么next[i]=size+1( 若没有 相同的部分,那么size=0,此时next[i]=1)
3.循环执行1,2,直至求出该模式串所有的next值
看此代码的next赋值语句,只有next[ j+1]=t+1才是赋值语句
,其他的都不是next赋值语句,当我们求next[j]的值时,其实是求next[j-1]+1,
从左到右递归关系,而对于next[j-1],我们知道next[j-]=t (设为t) 表示已知,这个过程已经用了KMP算法的思想,把模式串分为主串和模式串,然后进行前后缀对齐计算
2.1 next-val[]数组手算过程![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/eb44e9e6d0bb41a8ebafb3dfdbe349e0.png#pic_center)
为什么会有nextval[]数组?
当有大量重复的子字符串时,next[]数组会浪费一些时间去做无用的比较,人眼可以看出来
比如当比对到主串的B时,按照next[4]的调到3,拉出
然后A仍然不对,按照next[]数组,继续向前拉A,直至把
那为什么此时不直接拉到模式串的第一个字符进行比较呢?
这样就可以省去许多时间,上述重复的A,就是Pj=Pnext[j], A=A, j是当前位置,next[j]比j小,因此Pnex[j]在Pj左方,则此时nextval[j] = nextval[ next[j] ]
因此我们提出nextval[]数组对结果进行改善,
总结:
1. KMP算法保持主串指针不回溯
2. nex[]数组从左到计算,递推关系是next[j]=next[j-1]+1;
3. next[] 和 nextval[] 选一种即可,当你用代码计算next-val[]的时候,就没有必要计算next[]