zoukankan      html  css  js  c++  java
  • KMP&扩展KMP

    声明

    本文将不断加入例题,稍安勿躁,今天的总结争取9:30写完.

    KMP

    KMP,中文名字叫字符串匹配,用于解决一类字符串匹配问题.

    先下一些定义:

    • (s)表示匹配串,(t)表示文本串,字符串匹配用于求(s)(t)中的出现情况.
    • (n)(m)分别为(s)(t)的字符串串长.
    • (nxt_i)表示对于(s)的前缀(s_{1...i})的最长公共前后缀.

    首先我们先想一想(nxt_i)对于求解问题有怎样的帮助.

    暴力匹配

    我们对于每一个(t_i=s_1)的位置都匹配一次,这样子复杂度为(Theta(n*m))的.

    优化

    考虑在暴力匹配中其实我们不一定要重新匹配,因为你画一个图感性理解,发现如果匹配到了(s)(i)前缀,到(i+1)失配,其实是可以从(nxt_i)重新开始匹配的.

    这个时候(nxt_i)的好处就体现出来了,我们可以迅速再一次匹配.

    代码实现

    void KMP(){
    	nxt[1]=0;int j=0;
    	for(int i=2;i<=n;i++){
    		while(j && s[i]!=s[j+1])j=nxt[j];
    		if(s[i]==s[j+1])j++;nxt[i]=j;
    	}
    	j=0;
    	for(int i=1;i<=m;i++){
    		while(j && s[j+1]!=t[i])j=nxt[j];
    		if(t[i]==s[j+1])j++;
    		if(j==n){ans.push_back(i-n+1);j=nxt[j];}
    	}
    }
    

    扩展KMP

    (KMP)没有半毛钱关系,甚至和(KMP)的思想都没有半毛钱关系.

    问题引入

    有两个字符串(a),(b),要求输出(b)(a)的每一个后缀的最长公共前缀。

    还是和往常通过一样的,从暴力入手。

    暴力求解

    枚举每一个(a)的后缀然后与(b)匹配,复杂度(Theta(n*m))的.

    其他做法

    你当然可以(Hash),但是这与我们讨论的东西无关。

    优化

    我们大致画一下图(很重要)发现显然之前匹配过的位置如果包含这个(i)后缀的第一个字符,那么可以从那一个最长匹配开始.

    剩下的只需要不断像(manacher)一样匹配即可.

    代码实现

    for(int i=1,l=0,mx=0;t[i];i++){
    	z[i]=(i<mx)?min(z[i-l],mx-i):0;
    	while(t[i+z[i]]==t[z[i]])z[i]++;
    	if(i+z[i]>mx){l=i;mx=i+z[i];}
    }
    

    总结

    大致就是这样子了,今天还是有点东西的.

  • 相关阅读:
    Linux定时任务调度
    Linux组管理和权限管理
    Linux压缩和解压缩类指令
    leetcode:Compare Version Numbers
    leetcode:Valid Palindrome
    Majority Element
    Min Stack
    leetcode:Intersection of Two Linked Lists(两个链表的交叉点)
    leetcode:Factorial Trailing Zeroes
    leetcode:Rotate Array
  • 原文地址:https://www.cnblogs.com/fexuile/p/11623418.html
Copyright © 2011-2022 走看看