• 七月25 ACM集训——kmp算法


    字符串比配问题,通过引入next[]而使效率提高

    关于next[]数组,是对模式串的特征来构造的;

    为了确定在匹配不成功时,下次匹配时j的位置,引入了next[]数组,next[j]的值表示P[0...j-1]中最长后缀的长度等于相同字符序列的前缀。

    在匹配过程称,若发生不匹配的情况,如果next[j]>=0,则目标串的指针i不变,将模式串的指针j移动到next[j]的位置继续进行匹配;若next[j]=-1,则将i右移1位,并将j置0,继续进行比较。

    具体思想:

       根据定义next[0]=-1,假设next[j]=k, 即P[0...k-1]==P[j-k,j-1]

       1)若P[j]==P[k],则有P[0..k]==P[j-k,j],很显然,next[j+1]=next[j]+1=k+1;

       2)若P[j]!=P[k],则可以把其看做模式匹配的问题,即匹配失败的时候,k值如何移动,显然k=next[k]。

    要理解kmp中next数组的求法 看http://www.cnblogs.com/10jschen/archive/2012/08/21/2648451.html

    模板:

    求next[];

    void getNext(char *ss,int *next)
    {

        int  j = -1,  i = 0;
        next[0] = -1;
        while(i < len)
       {
              if(j == -1 || ss[i] == ss[j])
             {

    
    

                        i++;
                        j++;
                        next[i] = j;
             }
             else
            {
                       j = next[j];
            }
      }

    匹配字符串;

    int kmp_search(char const* src, int slen, char const* patn, int plen, int const* nextval, int pos)    

    {    

        int i = pos;    

        int j = 0;    

        while ( i < slen && j < plen )    

        {    

            if( j == -1 || src[i] == patn[j] )    

            {    

                ++i;    

                ++j;    

            }    

            else    

            {    

                j = nextval[j];              

                //当匹配失败的时候直接用p[j_next]与s[i]比较,    

                //下面阐述怎么求这个值,即匹配失效后下一次匹配的位置    

            }    

        }    

        if( j >= plen )    

            return i-plen;    

        else    

            return -1;    

    }    

    杭电1711

    这是一种看起来比较复杂的代码:

    #include <string> 
    #include <iostream>
    #include<cstdio>
    #include<cstring>
     
    using namespace std; 
    int src[1000501],prn[15001];
    int nextval[15001];
    template<typename S,typename T>
    void get_nextval(S const* ptrn, T plen, T* nextval)   
    {   
        int i = 0;  //注,此处与下文的代码实现二不同的是,i是从0开始的(代码实现二i从1开始)    
        nextval[i] = -1;   
        int j = -1;   
        while( i < plen-1 )   
        {   
            if( j == -1 || ptrn[i] == ptrn[j] )   //循环的if部分   
            {   
                ++i;   
                ++j;   
                //修正的地方就发生下面这4行   
                if( ptrn[i] != ptrn[j] ) //++i,++j之后,再次判断ptrn[i]与ptrn[j]的关系   
                    nextval[i] = j;      //之前的错误解法就在于整个判断只有这一句。   
                else   
                    nextval[i] = nextval[j];   
            }   
            else                                 //循环的else部分   
                j = nextval[j];   
        }   
    }   
     
     
    template<typename S,typename T> 
    int kmp_search(S const* src, T slen, S const* patn, T plen, T const* nextval, T pos)   
    {   
        T i = pos;   
        T j = 0;   
        while ( i < slen && j < plen )   
        {   
            if( j == -1 || src[i] == patn[j] )   
            {   
                ++i;   
                ++j;   
            }   
            else   
            {   
                j = nextval[j];             
                //当匹配失败的时候直接用p[j_next]与s[i]比较,   
                //下面阐述怎么求这个值,即匹配失效后下一次匹配的位置   
            }   
        }   
        if( j >= plen )   
            return i-plen+1;   
        else   
            return -1;   
    }   
     
    int   main() 

     int t,slen,plen,i,j,a;
     
         scanf("%d",&t);
     while(t--)
     {
      scanf("%d%d",&slen,&plen);
      for(i=0;i<slen;i++)
       scanf("%d",src+i);
      for(j=0;j<plen;j++)
      scanf("%d",prn+j);
        get_nextval(prn, plen, nextval); 
         a= kmp_search(src, slen, prn, plen, nextval, 0);
     printf("%d ",a);
     }
      
        return 0; 
    }  

    杭电1686

    #include <string> 
    #include <iostream>
    #include<cstdio>
    #include<cstring>
     
    using namespace std; 
    char src[1000500],prn[10050];
    int nextval[10050],slen,plen;

    void get_nextval( int plen)   
    {   
        int i = 0;  //注,此处与下文的代码实现二不同的是,i是从0开始的(代码实现二i从1开始)    
        nextval[i] = -1;   
        int j = -1;   
        while( i <= plen-1 )   
        {   
            if( j == -1 || prn[i] == prn[j] )   //循环的if部分   
            {   
                i++;   
                j++;   
                //修正的地方就发生下面这4行   
                //++i,++j之后,再次判断ptrn[i]与ptrn[j]的关系   
                    nextval[i] = j;      //之前的错误解法就在于整个判断只有这一句。      
            }   
            else                                 //循环的else部分   
                j = nextval[j];   
        }   
    }   
     
     
    int kmp_search( int slen,int plen)   
    {   
        int i = 0;   
        int j = 0,count=0;   
        while ( i < slen )   
        {   
            if( j == -1 || src[i] == prn[j] )   
            {  
                i++;   
                j++;
            }   
            else   
               j = nextval[j];             
                   
           if(j==plen)   
         count++;
        }   
          
            return count;     
    }   
     
    int   main() 

     int t,i,j,a;

        scanf("%d",&t);
         while(t--)
     {
      scanf("%s%s",prn,src);
         slen = strlen(src);
      plen = strlen(prn);
        
        get_nextval( plen); 
        a= kmp_search(slen,plen);

      printf("%d ",a);
     
        
     }
      
        return 0; 
    }  

  • 相关阅读:
    动态规划----查找一个数组中存在的数学数列
    java数据结构和算法------第八章
    java数据结构和算法-----第七章
    04002_HTML表单
    雷林鹏分享:PHP 高级过滤器
    雷林鹏分享:Lua 函数
    雷林鹏分享:Lua 流程控制
    雷林鹏分享:Lua 循环
    雷林鹏分享:Lua 变量
    雷林鹏分享:Lua 数据类型
  • 原文地址:https://www.cnblogs.com/ly---1287/p/3870519.html
Copyright © 2020-2023  润新知