七月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]。

模板:

求next[];

void getNext(char *p,int *next)
{
    int j,k;
    next[0]=-1;
    j=0;
    k=-1;
    while(j<strlen(p)-1)
    {
        if(k==-1||p[j]==p[k])    //匹配的情况下,p[j]==p[k]
        {
            j++;
            k++;
            next[j]=k;
        }
        else                   //p[j]!=p[k]
            k=next[k];
    }
}

匹配字符串;

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\n",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\n",a);
 
    
 }
  
    return 0; 
}

七月25 ACM集训——kmp算法

时间: 2024-11-10 10:20:53

七月25 ACM集训——kmp算法的相关文章

七月23 ACM集训——最小生成树

prim算法模板 int  prim(int x){    int i,j,sum=0,min=M,k; memset(vit,0,sizeof(vit));    memset(dis,0,sizeof(dis));    for(i=1;i<=m;i++)        dis[i]=p[x][i];    dis[x]=0;    vit[x]=1;     for(i=1;i<m;i++)    {        min=M;        k=-1;        for(j=1;j

2015年暑期ACM集训总结

今年暑假学校照例进行了ACM的暑假集训,跟以往不同的是:今年我作为一个老队员站上了讲台,体验了一把当老师的感觉,给新队员讲解ACM系列知识. 在集训开始之前,我跟一个同学写了一个ACM的评测系统,啊,评测系统?高达上啊.其实不然,这个系统也没有想象的那么复杂,只能简单地评测程序的几种状态: Compile Error Runtime Error Time Limit Exceeded Wrong Answer Accepted 所写的评测系统,是一个线下的评测系统,即只能本地上交程序,然后评测,

小谈KMP算法

刚接触KMP算法时,真是一头雾水,主要就是关于next跳转表是如何算出的,看了很久才勉强看明白,下面就是一点个人见解. 1.首先我要推荐先看这篇文章:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html 看完这篇文章之后能明白kmp的主要思路是什么了 字符串匹配的KMP算法 作者: 阮一峰 日期: 2013年5月 1日 字符串匹配是计算机的基本任务之一. 举例来说,有一个字

hiho 1015 KMP算法 &amp;&amp; CF 625 B. War of the Corporations

#1015 : KMP算法 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一只河蟹,于是河蟹就向小Hi和小Ho提出了那个经典的问题:“小Hi和小Ho,你们能不能够判断一段文字(原串)里面是不是存在那么一些……特殊……的文字(模式串)?” 小Hi和小Ho仔细思考了一下,觉得只能想到很简单的做法,但是又觉得既然河蟹先生这么说了,就

KMP算法

1 /* next数组是KMP算法的关键,next数组的作用是:当模式串T和主串S失配 2 * ,next数组对应的元素指导应该用T串中的哪一个元素进行下一轮的匹配 3 * next数组和T串相关,和S串无关.KMP的关键是next数组的求法. 4 * 5 * ——————————————————————————————————————————————————————————————————— 6 * | T | 9 | a | b | a | b | a | a | a | b | a | 7

跳跃表,字典树(单词查找树,Trie树),后缀树,KMP算法,AC 自动机相关算法原理详细汇总

第一部分:跳跃表 本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈"跳跃表"的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代码,以及本人对其的了解.难免有错误之处,希望指正,共同进步.谢谢. 跳跃表(Skip List)是1987年才诞生的一种崭新的数据结构,它在进行查找.插入.删除等操作时的期望时间复杂度均为O(logn),有着近乎替代平衡树的本领.而且最重要的一点,就是它的编程复杂度较同类

字符串的KMP算法替换

1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 6 7 class myString 8 { 9 private: 10 string mainstr; 11 int size; 12 void GetNext(string p,int next[]); 13 int KMPFind(string p,int next[]); 14 public: 15 myString(); 16 //~myS

字符串模式匹配KMP算法中的next数组算法及C++实现

一.问题描述: 对于两个字符串S.T,找到T在S中第一次出现的起始位置,若T未在S中出现,则返回-1. 二.输入描述: 两个字符串S.T. 三.输出描述: 字符串T在S中第一次出现的起始位置,若未出现,则返回-1. 四.输入例子: ababaababcbababc 五.输出例子: 5 六.KMP算法解析: KMP算法分为两步,第一步是计算next数组,第二步是根据next数组通过较节省的方式回溯来比较两个字符串. 网络上不同文章关于next数组的角标含义略有差别,这里取参考文献中王红梅<数据结构

通过图片对比带给你不一样的KMP算法体验

KMP 算法,俗称“看毛片”算法,是字符串匹配中的很强大的一个算法,不过,对于初学者来说,要弄懂它确实不易. 笔者认为,KMP 算法之所以难懂,很大一部分原因是很多实现的方法在一些细节的差异.体现在几个方面: next 数组,有的叫做“失配函数”,其实是一个东西: next 数组中,有的是以下标为 0 开始的,有的是以 1 开始的: KMP 主算法中,当发生失配时,取的 next 数组的值也不一样!就这样,各说各的,乱的很! 所以,在阐述我的理解之前,我有必要说明一下,我是用 next 数组的,