ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

kmp算法学习 与 传参试验(常回来看看)

2019-08-28 12:00:10  阅读:269  来源: 互联网

标签:传参 ch 常回来 int KMP next char len1 kmp


  之前在codeforces上做了一道类似KMP的题目,但由于之前没有好好掌握,现在又基本忘记,并没能解答。下面是对KMP算法的一点小总结。

  首先KMP算法的核心是纸在匹配过程中,利用模式串的前后缀来加速匹配过程,这一点在自己实验时就可以发现了。其次时KMP算法的核心Next数组,next[j]=k表示对于模式串的【0...j-1】位,最长存在长度为k的相同前后缀,值得注意的是对于kmp而言是不能出现next[j]=j的情况的。而next数组的计算方法我认为本质上还是DP,但是在状态转移过程中又用到了递归的想法,因此使得算法变得复杂。

  下面是codeforces上的next数组变种题:http://codeforces.com/contest/1200/problem/E

  需要利用next数组的思想,将要合并的两个字符串构建成“S2+S1"的形式,其中的“+”可以防止匹配越界,还应该注意构建时取S1.S2的最小长度从而减小时间复杂度。最后利用next[]的最后一位即可得到合并部分的长度。

  这里是自己比较习惯的利用for循环完成next数组构建的写法。

 #include <stdio.h>
 
char ch[1000010];
int next[1000010];
 
char* mmerge(char* ch1,char* ch2,int &len1,int len2)
{
   //printf("%d %d ",len1,len2);
    int len=len1;if (len2<len) len=len2;
 
    for (int i=0;i<len;i++)
        ch[i]=ch2[i];
    ch[len]='+';
    for (int i=len*2,j=len1-1;i>len;i--,j--)
        ch[i]=ch1[j];
    ch[len*2+1]=0;
   // printf("%s\n",ch);
 
    next[0]=0;
    for (int i=1;i<=len*2;i++)
    {
        int j=next[i-1];
        while (j && ch[i]!=ch[j])
            j=next[j-1];
        if ( ch[i]==ch[j] ) next[i]=j+1;
        else next[i]=0;
    }
 
    //printf(" %d ",next[len*2]);
    for(int i=next[len*2];ch2[i];i++,len1++ )
        ch1[len1]=ch2[i];
    ch1[len1]=0;
 
    //printf("%s\n\n",ch1);
    return ch1;
}
 
int main()
{
    char ch1[1000010];
    int n;scanf("%d",&n);
    scanf("%s",ch1);
    int len1=0;
    while (ch1[len1]) len1++;
    for(int i=1;i<n;i++)
    {
        char ch2[1000010];
        scanf("%s",ch2);
        int len2=0;while (ch2[len2]) len2++;
        mmerge(ch1,ch2,len1,len2);
    }
    printf("%s",ch1);
}
View Code

  也有正常使用while循环的写法(可能不标准吧)

#include <stdio.h>

char ch[1000010];
int next[1000010];

char* mmerge(char* ch1,char* ch2,int &len1,int len2)
{
    
    int len=len1;if (len2<len) len=len2;

    for (int i=0;i<len;i++)
        ch[i]=ch2[i];
    ch[len]='+';
    for (int i=len*2,j=len1-1;i>len;i--,j--)
        ch[i]=ch1[j];
    ch[len*2+1]=0;


    next[0]=0;
    int now=1,mlen=0;
    while (now<=len*2)
    {
        if (ch[now]==ch[mlen])
        {
            next[now]=mlen+1;
            now++;mlen++;
        }
        else
        if (mlen==0)
            next[now++]=0;
        else
            mlen = next[mlen-1];
    }

    for(int i=next[len*2];ch2[i];i++,len1++ )
        ch1[len1]=ch2[i];
    ch1[len1]=0;

    return ch1;
}

int main()
{
    char ch1[1000010];
    int n;scanf("%d",&n);
    scanf("%s",ch1);
    int len1=0;
    while (ch1[len1]) len1++;
    for(int i=1;i<n;i++)
    {
        char ch2[1000010];
        scanf("%s",ch2);
        int len2=0;while (ch2[len2]) len2++;
        mmerge(ch1,ch2,len1,len2);
    }
    printf("%s",ch1);
}
View Code

  在程序中,也大胆尝试了以前不敢用的传递对象指针以及利用引用&完成传值的操作,希望以后能多用一些这种编程方式,有利于工程实践。另外最开始将ch数组与next数组放置于mmerge函数中,似乎出现了栈溢出的问题(以后需要关注,还不太明白)。

  接着做了一道正常KMP例题,http://acm.hdu.edu.cn/showproblem.php?pid=1686,问S1在S2串中出现了多少次?

#include <stdio.h>

int ans( char* S, char* P, int* next )
{
    int aans=0;
    int len1=0;while (S[len1]) len1++;
    int len2=0;while (P[len2]) len2++;
    next[0]=-1;
    int now=0,mlen=-1;
    while (now<len1)
    {
        if (mlen==-1 || S[now]==S[mlen] )
        {
            mlen++;
            now++;
            next[now]=mlen;
        }
        else
            mlen=next[mlen];
    }

    int i=0,j=0;
    while (j<len2)
    {
        if (i==len1) aans++,i=next[i];
        if (i==-1 || S[i]==P[j])
            i++,j++;
        else
            i=next[i];

    }
    if (i==len1) aans++;
    return aans;

}

int main()
{
    int T;scanf("%d",&T);
    while (T--)
    {
        char ch1[10010];
        char ch2[1000010];
        scanf("%s%s",ch1,ch2);
        int next[10010];
        printf("%d\n", ans(ch1,ch2,next) );
    }
}
View Code

  对于KMP,目前理解了原理,自己也能写出代码,不过感觉还是不够熟练,时常回来看看吧:)

标签:传参,ch,常回来,int,KMP,next,char,len1,kmp
来源: https://www.cnblogs.com/askl123/p/11423227.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有