zoukankan      html  css  js  c++  java
  • 七月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; 
    }  

  • 相关阅读:
    AcWing 157. 树形地铁系统 (hash判断树同构)打卡
    AcWing 156. 矩阵 (哈希二维转一维查询)打卡
    AcWing 144. 最长异或值路径 01字典树打卡
    AcWing 143. 最大异或对 01字典树打卡
    AcWing 142. 前缀统计 字典树打卡
    AcWing 139. 回文子串的最大长度 hash打卡
    AcWing 138. 兔子与兔子 hash打卡
    常用C库函数功能及用法
    编程实现C库函数
    C语言面试题5
  • 原文地址:https://www.cnblogs.com/ly---1287/p/3870519.html
Copyright © 2011-2022 走看看