朴素的模式匹配
#include <iostream>
#include <string>
using namespace std;
int Match1(string str, string searchStr)
{
int i = 0;
int j = 0;
while (i < str.size() && j < searchStr.size())
{
if (str[i] == searchStr[j])
{
i++;
j++;
}
else//指针回退,重新开始匹配
{
i = i - j + 1;//目标串回到匹配位置的下一位置
j = 0;//模式串回到起始0位置
}
}
if (j >= searchStr.size())
{
return i - searchStr.size();//返回第一次匹配的首地址
}
else
{
return -1;
}
}
int main(){
string s = "goodgoogle";
string t = "google";
cout << Match1(s, t)<<endl;
}
参考:【数据结构】模式匹配算法
这种多数情况下m<<n所以认为时间复杂度是 O(m*n)
n:目标串长度
m:模式串长度
慢的原因是每次只向前一次,目标串的检测指针要回退
KMP算法
把模式匹配的时间复杂度降到O(n)
最关键的一步是nextKMP算法—终于全部弄懂了
void Getnext(int next[],String t)
{
int j=0,k=-1;
next[0]=-1;
while(j<t.length-1)
{
if(k == -1 || t[j] == t[k])
{
j++;k++;
next[j] = k;
}
else k = next[k];//此语句是这段代码最反人类的地方,如果你一下子就能看懂,那么请允许我称呼你一声大神!
}
}
这个博主说下面那行代码不太理解,但是我愚笨的脑袋连上面那些也不理解
主要是开始没看懂k是什么,next(j)是容易理解的
我们定义next是一个这样的辅助向量(其实可以理解为数组),和
这种信息就是对于每模式串 t 的每个元素 t j,都存在一个实数 k ,使得模式串 t 开头的 k 个字符(t 0 t 1…t k-1)依次与 t j 前面的 k(t j-k t j-k+1…t j-1,这里第一个字符 t j-k 最多从 t 1 开始,所以 k < j)个字符相同。如果这样的 k 有多个,则取最大的一个。模式串 t 中每个位置 j 的字符都有这种信息,采用 next 数组表示,即 next[ j ]=MAX{ k }。
————————————————
版权声明:本文为CSDN博主「June·DD」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dark_cy/article/details/88698736
是一样的
为什么k要<j-1?
要不next肯定是j-1,下次比较还是从pj比较就没有意义了
但是循环过程中的k是什么?
void Getnext(int next[],String t)
{
int j=0,k=-1;
next[0]=-1;
while(j<t.length-1)
{
if(k == -1 || t[j] == t[k])
{
j++;k++;
/*这里是先往下走一个下标,
再把k++也就是说实际上是确认的是j下一个位置的next值,所以上面while里也写的是j<t.length-1*/
next[j] = k;
}
else k = next[k];
}
}
但是之前的问题还没解决,而和else那句类似的问题,我们确定了一个next[j]为什么k不回退,k是什么东西.
我们先把next[0] = k
void Getnext(int next[],String t)
{
int j=0,k=-1;
next[0]=k;//实际上可以替换为k
while(j<t.length-1)
{
if(k == -1 || t[j] == t[k])
{
j++;k++;
/*这里是先往下走一个下标,
再把k++也就是说实际上是确认的是j下一个位置的next值,所以上面while里也写的是j<t.length-1*/
next[j] = k;
}
else k = next[k];
}
}
那么我们可以发现事实上每一个k都会对应一个next值,
next[j] = k;
时k是tj前k个元素和t0- t k-1匹配
这个时候如果t[j] == t[k]
那么tj+1 的前k+1个元素和t0- t k 匹配
k实际上就是从现在当前处理的tj开始向前k个(包括tj)和t0 - tk+1匹配else k = next[k];
这里的k其实和主函数里原理相同,相当于是从头开始的模式匹配
(以前半部分做主串,正在匹配的字符是模式串),那么这句话的意思就很清楚了:k回退到 next[k]的位置继续尝试和t~j~进行匹配
,
改进
void Getnext(int next[],String t)
{
int j=0,k=-1;
next[0]=-1;
while(j<t.length-1)
{
if(k == -1 || t[j] == t[k])
{
j++;k++;
if(t[j]==t[k])//当两个字符相同时,就跳过
next[j] = next[k];
else
next[j] = k;
}
else k = next[k];
}
}
如果t[j]==t[k]
那么tj匹配不上tk肯定也匹配不上
全部代码leetcode 28
这个题暴力也不会超时,但是可以学习kmp算法
int* getNext( string needle)
{
int n = needle.size();
int* next = new int[n+10];
int k = -1;
next[0] = k;
int i = 0;
while(i<n)
{
if(k== -1 ||needle[i]==needle[k])
{
i++;k++;
if(t[j]==t[k])//当两个字符相同时,就跳过
next[j] = next[k];
else
next[j] = k;
}
else
{
k = next[k];
}
}
return next;
}
int strStr(string haystack, string needle) {
int* next =getNext(needle);
int i=0,j=0,n=haystack.size(),ans=-1,p=needle.size();
while(i<n&&j<p)
{
if(j==-1||haystack[i]==needle[j])
{
i++,j++;
}
else
{
j= next[j];
}
}
if(j==p)
{
return i-j;
}
return ans;
}