KMP--作用、模板、题单总结(包含题解)

模板

#include <cstdio>
#include <cstring>
using namespace std;
int n;
char ts[100];
char ms[100];
int next[100];
int len;
 
void getNext()
{
    int i = 0, j = -1;
    next[0] = -1;
    while (i != len){
        if (j == -1 || ts[i] == ts[j]){
            next[++i] = ++j;
        }
        else
            j = next[j];
    }
}
int KmpMatch(char ms[], char ts[])
{
    int tlen = strlen(ts);
    for(int i = 0, j = 0; ms[i];)
    {
        if(j == -1 || ms[i] == ts[j])
        {
            if(j == tlen - 1)
                return i - tlen + 1;
            else 
                i++, j++;
        }
        else 
            j = next[j];
    }
    return -1;
}

Next数组的各种操作

  • 求最小循环节

看案例意会即可

if (len % (len - nxt[len]) == 0)
	printf("%d\n", len - nxt[len]);

2
abcabcabcabc
-1000123456789
  • next数组的规格

能求到next[n]这一位。

  • 在一个字母序列中,求有没有字母序列在前缀、后缀以及中间都出现。

既然要求三个相同的子串,而且有两个还必须在开头和结尾,那就求Next数组,Next数组存的是前后缀相同的长度,所以只需要找【2*i,L-Next[i]】之间相同的字串,即Next[j]==i;

  • 找循环串的每一个结束

    while(nex[len] != 0)
    {
    	q.push(nex[len]);
    	len = nex[len];
    }
    while(!q.empty())
    {
    	printf("%d ",q.top());
    	q.pop();
    }
    
  • 补全循环串的最小个数

    (len -nex[len]) -len %(len-nex[len])
    

KmpMatch函数里的各种操作

  • 求有多少个可分开的子串

    int KmpMatch(char ms[],char ts[])
    {
        BuildNext( ts);
        int tlen = strlen(ts);
        for(int i = 0,j = 0; ms[i]; )
        {
            if(j == -1 || ms[i] == ts[j])
            {
            	//这一段是关键
                if(j == tlen-1 )
                {
                   con++;
                   j = 0;
                   i++;
                }
                else
                    i++,j++;
            }
            else
                j  = nex[j];
        }
        return -1;
    }
    
  • 求有多少个可以重复的子串

    int KmpMatch(char ms[],char ts[])
    {
        int cnt = 0;
        int tlen = strlen(ts);
        for(int i = 0,j = 0; ms[i]; )
        {
            if(j == -1 || ms[i] == ts[j])
            {
                i++;
                j++;
                if(j == tlen)
                {
                    //这里是关键
                    j = nex[j];
                    cnt ++;
                }
            }
            else j = nex[j];
        }
        return cnt;
    }
    

例题

Uva 445 Periodic Strings

#include <cstdio>
#include<iostream>
#include <cstring>
using namespace std;
char str[100];
int nxt[100];
int len;
void getNext()
{
    int i = 0, j = -1;
    nxt[0] = -1;
    while (i != len){
        if (j == -1 || str[i] == str[j]){
            nxt[++i] = ++j;
        }
        else
            j = nxt[j];
    }
}
int main()
{
    scanf("%d", &n);
    while (n--){
        scanf("%s", str);
        len = strlen(str);
        getNext();
        if (len % (len - nxt[len]) == 0)
            printf("%d\n", len - nxt[len]);
        else
            printf("%d\n", len);
        if (n)
            printf("\n");
    }
    return 0;
}

hdu 剪花布条

#include<cstdio>
#include<cstring>
using namespace std;

int nex[100000];
int con;
void BuildNext(char ts[])
{
    nex[0] = -1;
    for(int i = 0, j = -1;ts[i]; )
    {
        if(j == -1 || ts[i] == ts[j])
            nex[++i] = ++j;

        else j = nex[j];
    }
}

int KmpMatch(char ms[],char ts[])
{
    BuildNext( ts);
    int tlen = strlen(ts);
    for(int i = 0,j = 0; ms[i]; )
    {
        if(j == -1 || ms[i] == ts[j])
        {
            if(j == tlen-1 )
            {
               con++;
               j = 0;
               i++;
            }
            else
                i++,j++;
        }
        else
            j  = nex[j];
    }
    return -1;
}

int main()
{
   char ms[10000];
   char ts[10000];
   while(scanf("%s",&ms))
   {
       if(ms[0] =='#') return 0;
       scanf("%s",&ts);
        con = 0;
       KmpMatch(ms,ts);
       printf("%d\n",con);

   }
}

hdu 4847 Wow!Such Doge!

#include<iostream>
#include<cstdio>
#include<cstring>

int doge[10];
int dogE[10];
int doGe[10];
int doGE[10];
int dOge[10];
int dOgE[10];
int dOGe[10];
int dOGE[10];
int Doge[10];
int DogE[10];
int DoGe[10];
int DoGE[10];
int DOge[10];
int DOgE[10];
int DOGe[10];
int DOGE[10];
void Buildnext(int as[],const char ts[])
{
    as[0] = -1;
    for(int i = 0, j = -1; ts[i]; )
    {
        if(j == -1 || ts[i] == ts[j])
            as[++i] = ++j;
        else j = as[j];
    }
}

void init_next()
{
    Buildnext(doge,"doge");
    Buildnext(dogE,"dogE");
    Buildnext(doGe,"doGe");
    Buildnext(doGE,"doGE");
    Buildnext(dOge,"dOge");
    Buildnext(dOGe,"dOGe");
    Buildnext(dOGE,"dOGE");
    Buildnext(Doge,"Doge");
    Buildnext(DogE,"DogE");
    Buildnext(DoGe,"DoGe");
    Buildnext(DoGE,"DoGE");
    Buildnext(DOge,"DOge");
    Buildnext(DOgE,"DOgE");
    Buildnext(DOGe,"DOGe");
    Buildnext(DOGE,"DOGE");
    Buildnext(dOgE,"dOgE");
}

int KmpMatch(char ms[], int nex[], const char ts[])
{
    int cnt = 0;
    for(int i = 0,j = 0;ms[i]; )
    {
        if(j == -1 || ms[i] == ts[j])
        {
            i++;
            j++;
        }
        else j = nex[j];
        if(j == strlen(ts))
        {
            cnt++;
            j = 0;
        }
    }
    return cnt;
}
int main()
{
    int cnt = 0;
    char s1[100000];
    init_next();
    while(scanf("%s",&s1)!= EOF)
    {
        cnt +=KmpMatch(s1,doge,"doge")+KmpMatch(s1,dogE,"dogE")+KmpMatch(s1,doGe,"doGe")+KmpMatch(s1,doGE,"doGE");
        cnt +=KmpMatch(s1,dOge,"dOge")+KmpMatch(s1,dOgE,"dOgE")+KmpMatch(s1,dOGe,"dOGe")+KmpMatch(s1,dOGE,"dOGE");
        cnt +=KmpMatch(s1,Doge,"Doge")+KmpMatch(s1,DogE,"DogE")+KmpMatch(s1,DoGe,"DoGe")+KmpMatch(s1,DoGE,"DoGE");
        cnt +=KmpMatch(s1,DOge,"DOge")+KmpMatch(s1,DOgE,"DOgE")+KmpMatch(s1,DOGe,"DOGe")+KmpMatch(s1,DOGE,"DOGE");
    }
    printf("%d\n",cnt);

}

hdu 1686、poj 3461 Oulipo

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int nex[1000000];

void Buildnext(char ts[])
{
    nex[0] = -1;
    for(int i = 0,j  = -1; ts[i]; )
    {
        if(j == -1 ||ts[i] == ts[j])
            nex[++i] = ++j;
        else j = nex[j];
    }
}

int KmpMatch(char ms[],char ts[])
{
    int cnt = 0;
    int tlen = strlen(ts);
    for(int i = 0,j = 0; ms[i]; )
    {
        if(j == -1 || ms[i] == ts[j])
        {
            i++;
            j++;
            if(j == tlen)
            {
                j = nex[j];
                cnt ++;
            }
        }
        else j = nex[j];


    }
    return cnt;
}

int main()
{
    int t;
    cin>>t;

    while(t--)
    {
        char ts[10000000], ms[10000000];
        scanf("%s %s",&ts,&ms);
        Buildnext(ts);
        printf("%d\n", KmpMatch(ms,ts));

    }
}

hdu 1711 Number Sequence

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int ts[1000000], ms[1000000];
int nex[1000000];
void Buildnext(int ts[],int len2)
{
    nex[0] = -1;
    for(int i = 0,j  = -1; i<=len2; )
    {
        if(j == -1 ||ts[i] == ts[j])
            nex[++i] = ++j;
        else j = nex[j];
    }
}

int KmpMatch(int ms[],int ts[],int tslen, int len)
{
    int cnt = 0;
    int tlen = tslen;
    for(int i = 0,j = 0; i<len; )
    {
        if(j == -1 || ms[i] == ts[j])
        {
             i++,j++;
        }
        else j = nex[j];
        if(j == tlen )
            {
                return i- tlen + 1;
            }
    }
    return -1;
}

int main()
{
    int t;
    scanf("%d",&t);

    while(t--)
    {

        int len,len2;
        scanf("%d%d",&len,&len2);
        for(int i = 0;i<len; i++) scanf("%d",&ms[i]);
        for(int i = 0;i<len2; i++) scanf("%d",&ts[i]);
        Buildnext(ts,len2);
        int ans =  KmpMatch(ms,ts,len2, len);
        printf("%d\n",ans);

    }
}

hdu 4763 Theme Section(参考)

思路:

既然要求三个相同的子串,而且有两个还必须在开头和结尾,那就求Next数组,Next数组存的是前后缀相同的长度,所以只需要找【2*i,L-Next[i]】之间相同的字串,即Next[j]==i;

#include<stdio.h>
#include<string.h>
#include<string>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N=1000005;
 
char s[N];
int Next[N],l;
 
void get_Next()
{
    int i=0,j=-1;
    Next[0]=-1;
    while(i<l)
    {
        if(j==-1||s[i]==s[j])
            Next[++i]=++j;
        else
            j=Next[j];
    }
}
 
int KMP()
{
    int i,j;
    for(i=Next[l]; i; i=Next[i])
        for(j=2*i; j<=l-i; j++)
            if(Next[j]==i)
                return i;
    return 0;
}
 
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",s);
        int ans=0,k,i,j;
        l=strlen(s);
        get_Next();
//        for(i=1; i<=l; i++)
//            printf("%d ",Next[i]);
//        printf("\n");
        printf("%d\n",KMP());
    }
    return 0;
}

参考:https://blog.csdn.net/qq_41984014/article/details/81626493?ops_request_misc=&request_id=&biz_id=102&utm_term=theme%20section&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-1-81626493.nonecase&spm=1018.2226.3001.4187

poj 2046 Power Strings

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int nex[1000005];
char ms[1000005];
int cnt;
void BuildNext()
{
    nex[0] = -1;
    for(int i =0,j = -1;ms[i]; )
    {
        if(j == -1 || ms[i] == ms[j])
            nex[++i] = ++j;

        else j = nex[j];
    }
}
int main()
{
    int cyc;
    while(scanf("%s",&ms)!= EOF && strcmp(ms,".") != 0 )
    {
            BuildNext();
            int len = strlen(ms);
           
            cyc = len - nex[len];

            if(len %cyc == 0)
                printf("%d\n", len /cyc);
            else
                printf("1\n");
    }
    return 0;
}

poj 2752 Seek the Name, Seek the Fame

#include<cstdio>
#include<iostream>
#include<cstring>
#include<stack>
using namespace std;
int nex[1000000];
char ms[1000000];
int cnt;
void BuildNext()
{
    nex[0] = -1;
    for(int i =0,j = -1;ms[i]; )
    {
        if(j == -1 || ms[i] == ms[j])
        nex[++i] = ++j;

        else j = nex[j];
    }
}

int main()
{
    while(scanf("%s",&ms) != EOF)
    {
        stack<int>q;
        int len  = strlen(ms);
        BuildNext();
        q.push(len);
        while(nex[len] != 0)
        {
            q.push(nex[len]);
            len = nex[len];
        }
        while(!q.empty())
        {
            printf("%d ",q.top());
            q.pop();
        }
        printf("\n");
    }
}

poj 2185 Milking Grid (难题)

#include<iostream>
#include<cstring>
#include<iostream>
using namespace std;
char cow[10010][80];
char rvercow[80][10010];

int nexrow[10010];
int nexcol[10010];

int row,col;

void getnexrow()
{
    int j = -1,k = 0;
    nexrow[0] = -1;
    while(k < row)
    {
        if(j == -1 || !strcmp(cow[k],cow[j]))
        {
            k++;
            j++;
            nexrow[k] = j;
        }
        else j = nexrow[j];
    }
}

void getnexcol()
{
    int j = -1,k = 0;
    nexcol[0] = -1;
    while(k < col)
    {
        if(j == -1 ||!strcmp(rvercow[k],rvercow[j]))
        {
            j++,k++;
            nexcol[k] = j;
        }
        else
            j = nexcol[j];
    }
}

int main()
{
    while(cin>>row>>col)
    {
        for(int i =0;i < row;i++)
            cin>>cow[i];
        getnexrow();

        for(int i =0; i<row; i++)
            for(int j = 0; j<col; j++)
                rvercow[j][i] = cow[i][j];
        getnexcol();

        int minn = (row - nexrow[row]) * (col - nexcol[col]);
        cout<<minn<<endl;

    }
    return 0;
}

poj 3080 Blue Jeans

#include<iostream>
#include<cstring>
#include<string>
using namespace std;

int nex[1000000];
void BuildNex(string t)
{
    nex[0] = -1;
    int i = 0,j = -1;
    int len = t.length();
    while(i <len)
    {
        if(j == -1 || t[i] == t[j])
        {
            nex[++i] = ++j;
        }
        else j = nex[j];
    }
}
int kmp(string s,string t)
{
    int i = 0, j = 0;
    int lens = s.length(),lent = t.length();
    while(i < lens && j <lent)
    {
        if(j == -1 || s[i] == t[j])
            i++,j++;
        else j = nex[j];

        if(j == lent)
            return i-j+1;
    }
    return -1;
}
int main()
{
    int nn;
    scanf("%d",&nn);
    string s[15];
    while(nn--)
    {
        int n;
        cin>>n;
        for(int i = 0; i<n;i++) cin>>s[i];
        string t;
        string res;
        int ma = 0;
        for(int i = 0;i < 60;i++)
        {
            for(int j = i+1; j<= 60;j++)
            {
                t = string(s[0].begin()+i,s[0].begin()+j);
                BuildNex(t);
                int f = 0;
                for(int k = 1;k<n; k++)
                {
                    if(kmp(s[k],t) == -1)
                    {
                        f = 1;
                        break;
                    }
                }

                if(!f)
                {
                    if(ma<= j-i)
                    {
                        if(ma<j-i) res = t;
                        else res = min(res,t);
                        ma = j - i;
                    }
                }
            }
        }
        if(ma <3) printf("no significant commonalities\n");
        else
            cout<<res<<endl;
    }

}

hdu 1358 Period

#include<cstdio>
#include<iostream>
using namespace std;

int nex[1000005];
char ts[1000005];
void Buildnex(char ts[])
{
    nex[0] = -1;
    for(int i = 0, j = -1;ts[i]; )
    {
        if(j == -1 || ts[i] == ts[j])
            nex[++i] = ++j;
        else j = nex[j];
    }


}
int times;
int main()
{
    int t;
    times = 0;
    while(scanf("%d",&t)!=EOF)
    {
        if(t == 0)
            return 0;
        times++;

            scanf("%s",ts);

        Buildnex(ts);
        printf("Test case #%d\n",times);
        for(int i = 2;i<=t;i++)
        {
            if(i%(i-nex[i]) == 0 && i/(i-nex[i]) > 1)
            {
                cout<<i<<" "<<i/(i-nex[i])<<endl;
            }
        }
        cout<<endl;
    }

}

hdu 3746 Cyclic Nacklace

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int nex[1000005];
char ts[1000005];

void Buildnex(char ts[])
{
    nex[0] = -1;
    for(int i =0,j = -1;ts[i]; )
    {
        if(j == -1 || ts[i] == ts[j])
        {
            nex[++i] = ++j;
        }
        else j = nex[j];
    }
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        scanf("%s",&ts);
        Buildnex(ts);
        int len = strlen(ts);
        if(len % (len -nex[len]) == 0 && len != (len -nex[len]))
            cout<<0<<endl;
        else
        cout<<(len -nex[len]) -len %(len-nex[len])<<endl;

    }
}
  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 目描述 给定两个字符串 S 和 T,要求在 S 中找到 T 出现的所有位置。 输入格式 第一行输入一个整数 N,表示字符串 S 的长度。 第二行输入字符串 S。 第三行输入一个整数 M,表示字符串 T 的长度。 第四行输入字符串 T。 输出格式 输出所有匹配的位置,每个位置占一行。 如果不存在匹配的位置,输出 -1。 样例 输入样例: 13 ababcabcacbab 3 abc 输出样例: 2 5 8 算法1 (暴力枚举) $O(nm)$ 暴力枚举,时间复杂度 $O(nm)$。 时间复杂度 参考文献 python3 代码 C++ 代码 算法2 (KMP) $O(n+m)$ 时间复杂度 参考文献 C++ 代码 ### 回答2: KMP算法是字符串匹配的经典算法之一,在实际应用中具有非常广泛的应用,尤其是在文本处理、搜索引擎、数据挖掘等领域中都占有非常重要的地位。 KMP算法的核心思想是,当在匹配字符串中发现不匹配的字符时,可以利用已经匹配的部分信息来避免不必要的回溯,从而提高匹配效率。其具体实现的步骤如下: 1. 对于模式串P,求出其每个位置i对应的最长前缀后缀匹配长度next[i],即next[i]表示P[0:i-1]中最长的既是P的前缀又是P的后缀的子串长度。 2. 在匹配过程中,当主串T与模式串P的某个位置不匹配时,利用已经匹配的部分信息,将模式串向后移动j-next[j]个字符,再次进行匹配。 3. 如果模式串P已经完全匹配了主串T,则表示在T中找到了P,返回匹配的位置。 KMP算法的时间复杂度为O(n+m),其中n和m分别是主串T和模式串P的长度。相比经典的暴力匹配算法,KMP算法显著提高了匹配的效率,其核心思想也为其他字符串匹配算法的优化提供了宝贵的思路。 ### 回答3: kmp字符串匹配算法是一种高效的字符串匹配算法,它可以在O(n+m)的时间内完成字符串匹配,其中n为文本串的长度,m为模式串的长度。 kmp算法的实现是基于一个模式串前缀数组next数组的构建,next数组表示每个前缀的最长公共前后缀的长度。在匹配文本串和模式串的时候,通过比较匹配过程中的next值来实现跳过多余的比较操作,从而提高匹配效率。 具体的kmp算法实现步骤如下: 1. 构建模式串的前缀数组next数组 2. 在文本串上匹配模式串,比较过程中利用next数组进行跳过多余比较操作。 构建next数组的方法是通过对模式串本身进行遍历,求解每个前缀的最长公共前后缀长度。以模式串“ABABC”的前缀数组为例,其可以表示为: - A的前缀为空集,所以next[0]=-1 - AB的前缀为A,不存在公共前后缀,所以next[1]=0 - ABA的前缀为A和AB,不存在公共前后缀,所以next[2]=0 - ABAB的前缀为A、AB和ABA,前两个前缀没有公共前后缀,最后一个前缀的公共前后缀为A,所以next[3]=1 - ABABC的前缀为A、AB、ABA和ABAB,前三个前缀没有公共前后缀,最后一个前缀的公共前后缀为AB,所以next[4]=2 在匹配文本串和模式串的时候,可以利用next数组来跳过多余的比较操作。当匹配过程中发现模式串与文本串不匹配时,可以根据next数组的值进行模式串的移动,移动的长度为失配字符对应的next值。例如,在文本串“ABABABABC”和模式串“ABABC”匹配过程中,当发现模式串的第三个字符B与文本串的第六个字符C不匹配时,可以根据next[2]的值2将模式串的位置移动到第三个字符B处,而不需要将模式串从头开始进行匹配。 总之,kmp算法的主要思想是通过构建模式串的前缀数组来实现跳过多余的比较操作,在匹配过程中提高效率。其时间复杂度为O(n+m),是一种常用的字符串匹配算法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值