1 条题解

  • 1
    @ 2024-7-20 15:43:41

    本蒟蒻的第6篇题解——KMP

    看这道题就是问p在s中出现了多少次,若按照暴力,就是两个指针,p[i]与s[j]一个一个比,如下

    for(int i=1;i<=p.size();i++){
    for(int j=1;j<=s.size();j++){
    .......
    

    用脚趾头想都知道,这样做肯定会TLE,那么,就可以用到KMP


    我们可以去跳过某些没必要比对的;去直接比对需要的!接下来,要了解两个东西,前缀和后缀,现在假设这对 字符串p 的前后缀长度为 k 若这一对前后缀相同,则代表着下次移动,可以移动把前缀移到后缀处,例如aba 当 k 取1时,不难发现,前缀=a,后缀=a,则在ababa中,可以把指针i移动到第三个点,

    ababa
    aba
    ——>
    
    ababa
      aba
    

    可能有些难以理解,实在不懂就看看《信息学奥赛 一本通算法高效进阶(上册)》

    这样做,不难发现,省去了模拟

    ababa
     aba
    

    节省了更多的时间!

    以下为判断前后缀:

    for(int i=2,j=0; i<=n; i++) {
        while(j&&p[j+1]!=p[i]) j=ne[j];判断是否相同,相同就把下次移动定到后缀最前。
        if(p[j+1]==p[i]) j++;//对齐
        ne[i]=j;
    }
    

    而后的代码是判断,这里与暴力基本一样的思路,就是一个个判断

    for(int i=1,j=0; i<=m; i++) {
        while(j&&p[j+1]!=s[i]) j=ne[j];
        if(p[j+1]==s[i]) j++;
        if(j==n) {
            cout<<i-n<<' ';
            j=ne[j];
        }
    }
    

    这样整个题目便基本做出来了,如果发现有讲错的,欢迎指正!

    完整代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N=1e6+10;
    char s[N],p[N];
    int n,m,ne[N];
    int main() {
        cin>>n>>p+1>>m>>s+1;
        for(int i=2,j=0; i<=n; i++) {
            while(j&&p[j+1]!=p[i]) j=ne[j];
            if(p[j+1]==p[i]) j++;
            ne[i]=j;
    }
    for(int i=1,j=0; i<=m; i++) {
        while(j&&p[j+1]!=s[i]) j=ne[j];
        if(p[j+1]==s[i]) j++;
        if(j==n) {
            cout<<i-n<<' ';
            j=ne[j];
            }
        }
        return 0;
    }
    
    • 1

    信息

    ID
    358
    时间
    1000ms
    内存
    128MiB
    难度
    10
    标签
    递交数
    3
    已通过
    3
    上传者