模拟匹配法
程序优化
- 1.固定i的位置
 - 2.匹配失败时待匹配数组尽量向右挪动
 
情景模拟
- 文本串: BBC_ABCDAB_ABCDABCDABDE
 - 模式串: ABCDABD
 - 匹配失败时,希望向右跳的尽量远
 
i = 4 , j = 6 时,s[i+j] 与 p[j]匹配失败
BBC_ ABCDABABCDABCDABDE
ABCDABD
BBC ABCDAB_**
最多 ABCDABD
找到匹配失败时最远移动距离的位置,并记录
如果还是匹配不成功,则继续向左跳转
next[i]表示以第i个字符结尾时的最长前后缀相等部分的长度
(不做偏移)
next数组
• next数组用来记录匹配失败时需要跳转到的下一个位置
• 匹配思路
对于模式串P,递推求解next:
1.如果P[next[i-1]==P[i],则有next[i]=next[i-1]+1。
2.如果P[next[i-1]] \ne P[i]
令 j = next[i-1]
不断比较P[j]和P[i],不相同则令j=next[j-1],直到P[j]=P[i]或者j=0。
相当于
- 
文本串: ABCDABD
 - 
模式串: ABCDABD
 - 
字符串 A B C D A B D
 - 
下标 0 1 2 3 4 5 6
 - 
next数组 :
 - 
初始化 next[0] = 0
 - 
自己和自己匹配
 - 
next数组用来记录匹配失败时需要跳转到的下一个位置
 - 
匹配思路
 - 
1.最外层的i固定从头到尾移动
 - 
2.如果当前的p[i]==p[j],则让j++
 - 
3.如果当前的p[i]!=p[j],则让整个p串继续向右移动,同样也是跳到尽可能远的位置(相当于j向左移动)
 - 
4.设置next[i] = j
 
模板代码
#include <iostream>
#include <cstring>
const int N = 1000000 + 5000;
char ch1[N];
char ch2[N];
int len1,len2;
int next[N];
long long ans = 0;
void get_next(char* ch2)
{
    int j = 0;
    for (int i = 1 ; i < len2 ; i ++)
    {
        while (j != 0 && ch2[i] != ch2[j])
        {
            j = next[j - 1];
        }
        if (ch2[i] == ch2[j]) j ++;
        next[i] = j;
    }
}
void kmp(char* ch1,char* ch2)
{
    int j = 0;
    for (int i = 0 ; i < len1 ; i ++)
    {
        while (j != 0 && ch1[i] != ch2[j])
        {
            j = next[j - 1];
        }
        if (ch1[i] == ch2[j])
        {
            j ++;
        }
        if (j == len2)//匹配成功 
        {
            ans ++;
            j = next[j - 1];
        }
    }
}
int main()
{
    std :: cin >> ch1 >> ch2;
    len1 = strlen(ch1);
    len2 = strlen(ch2);
    get_next(ch2);
    kmp(ch1,ch2);
    std :: cout << ans;
}