• KMP算法(学习笔记)


    KMP用于线性时间内处理字符串匹配问题.

    KMP算法的代码实现不难,难点在于对失配指针,也就是next数组的理解.

    关于这个理解,各种神犇的博客都有很全面地分析,我就不再过多地赘述了,只结合代码简单分析一下.

    首先,KMP算法就两个部分,而且还长得特别地像.

    第一个部分是预处理,也就是模式串B(用来匹配的串)的"自我匹配"过程,这个过程是用来求next数组的.

    第二个部分是B与主串A(等待匹配的串)的匹配过程.

    我们用i,j指针表示(A[i-j+1...i])(B[1...j])完全相等.i是主串A的指针,它在不断地变化,随着i的增加,模式串B的指针j也应相应地变化,才能始终保证上述"(A[i-j+1...i])(B[1...j])完全相等".

    那么指针j应该如何"相应地变化"呢?就引入了next数组.

    (next[j])记录的是当模式串B匹配到下标j位置时,不能再与主串A匹配下去(即当(A[i+1]!=B[j+1])时),指针j能够向前跳到的(下标)最大位置.这个位置(假设下标是k),应当满足的条件是(B[1...k]=B[j-k+1...j]),简单来说就是既然我们不能保证B串的前j个都能匹配了,那么退而求其次,我可以保证B串的前k个(k<j)仍然匹配(如果这也是奢望,那就一直退而求其次,直到不能再退,即k=0)

    
    int j=0;
    nxt[1]=0;
    //初始化:匹配到第一个位置不能匹配了,那就只能到0了
    for(int i=1;i<n;i++){
    	while(j>0&&s2[i+1]!=s2[j+1])j=nxt[j];
    //不能继续匹配且j还没减到0,考虑退一步
    	if(s2[i+1]==s2[j+1])j++;
    //能匹配,j的值+1
    	nxt[i+1]=j;
    //记录第i+1个位置的失配指针位置
    }
    

    第二个部分就是由B串自己跟自己匹配变为B串与A串匹配,所以过程是极其相似的.

    int j=0;
    for(int i=0;i<m;i++){
    	while(j>0&&s1[i+1]!=s2[j+1])j=nxt[j];
    	if(s1[i+1]==s2[j+1])j++;
    	if(j==n){
    	    printf("%d
    ",i+1-n+1);
    //模式串(子串)串首在主串(母串)中的位置
    		ans++;
    //模式串(子串)在主串(母串)中的出现的次数
    	    j=nxt[j];
    //这里是为了让程序继续运行下去
    //因为有可能后面还有合法的匹配.
    	}
    }
    

    KMP模板(用上面这两段就能应付了)

    [BOI2009]Radio Transmission 无线传输

    题意:给你一个字符串,它是由某个字符串不断自我连接形成的.但是这个字符串是不确定的,现在只想知道它的最短长度是多少?

    样例输入:

    8

    cabcabca

    样例输出:

    3

    样例解释:abc,cab,bca都符合题意.

    本题灵活运用到了next数组的性质:(next[j])能够始终保证(B[1...j]=B[i-j+1...i]),本题的实质就是求字符串的循环节,所以j与(next[j])的距离就是本题的答案.(前提是(next[j])不为零),所以输出(n-next[n])最可靠.

    [POI2006] OKR-Periods of Words

    本题难点在于读懂题意,题目意思就是给定一个字符串,对于该字符串的每一个前缀x,求该前缀x的 最长的前缀y,且满足x又是yy(相当于两个y合并)的前缀.答案就是所有的这些最长的且符合要求的前缀的长度之和.

    根据next数组的性质,我们只要让失配指针一直失配下去,直到不能失配为止(即到达边界下标0处)

    long long ans=0;//十年oi一场空...
    for(int i=1;i<=k;i++){
    	if(nxt[nxt[i]])
        	nxt[i]=nxt[nxt[i]];
    }
    for(int i=1;i<=k;i++)
    	if(nxt[i])ans+=i-nxt[i];
    printf("%lld
    ",ans);
    

    小结一下,KMP算法的代码不难实现,但重点是能够理解next数组,失配指针的含义,从而能够得到很多性质.而大多数有关KMP算法的题目就是利用这些性质来巧妙解题的,代码量都不会很大.

  • 相关阅读:
    Hdoj 3697 Selecting courses 【贪心】
    nginx 反向代理
    嵌入式交叉编译环境搭建
    OpenWrt编译
    OpenWrt for vmware 从openwrt.org下载10.03.1 或是自己下载最新的源码进行编译生成x86 vmdk格式
    ubuntu centos debina
    openWRT
    C++ classics
    tomcat配置访问日志,访问首页主目录
    apache http配置https
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10326685.html
Copyright © 2020-2023  润新知