BF.KR.KMP匹配思路
1.字符串的模式串匹配问题(含KMP)
前置说明,字符串s长度m,模式串p长度n
1.1BF算法
1.1.1利用循环进行暴力匹配,时间复杂度O(mn)
1.2KR(Karp-Rabin)算法
1.2.1利用滑动窗口内容逐一匹配
1.2.2将滑动窗口内的m个字符的比较变为一个哈希值的比较
时间复杂度O(n)
1.3KMP算法
1.3.1匹配思路:
匹配过程中,对于已经匹配好的p串的子串进行重复利用,i指针指向s串,j指针指向p串,正常匹配的话,i++,j++,当发生匹配失败的时候,我们仅仅需要向前移动j指针,即将j指针移动到j之前的那个子串的前缀能匹配后缀的最大长度的位置,那么怎样移动j指针呢?我们可以用一个next[]数组来记录将j往前移动的位置。
void get_next(char next[],string p)
{
next[0] = 0; next[1] = 0;
int j = 0; int i = 2;
while (i <= p.size())
{
if (j==0||p[i - 1] == p[j])
{
j += p[i - 1] == p[j];
next[i++] = j;
}
else
j = next[j];
}
}
1.3.2图片描述:看图顺序为绿色->黑色->紫色->蓝色
绿色:是已经匹配好了的最长公共前后缀
黑色:是正在匹配的字符,并且是那种不匹配的字符
紫色:是不匹配的情况下,向前递归寻找的的可执行的位置
蓝色:是递归寻找到了的可移动到的位置
说明:所有相同颜色框起来的字符串都是相同的
j的位置已经标出来了,右下角空心箭头指的位置是i的位置
1.3.3KMP匹配思路
在匹配过程中,我们不断向右移动指针i,如果i,j所指向的字符相同,则同时移动j指针,如果指向的字符不同,则利用next数组将j不断向前回溯,直到j指针所指的内容与i相同 || j指向了0位置。当j匹配完了pa模式串之后,我们可以利用i,j的位置找到被匹配的字符的位置。
参考代码:
for (int i = 0; i < s.size(); i++)
{
if (pa[j] == s[i])
j++;
else
{
while (j != 0 && s[i] != pa[j])
j = next[j];
if (s[i] == pa[j])
j++;
}
if (j == pa.size())
{
int po = i - j + 2;
cout << po << endl;
j = next[j];
}
}