• KMP:n+1次探


    如你所见,这是我不知道第几次学KMP了。
    推荐B站上电子科大的字符串专题。

    引入:KMP是干什么的

    KMP解决的是模式串P在源串T中出现次数的问题,比如模式串P为aba,源串为abababa,我们可以求出计算重叠的出现次数3,还可以求出不计算重叠的出现次数2。

    next数组

    • [x] 最好不要用next命名next数组,某些OJ会报错
    前(后)缀和真前(后)缀:字符串s前i个(i<=strlen(s))字符为其前缀,i!=strlen(s)时为真前缀,后缀和真后缀同理。

    next[i]表示模式串P以i为尾的这个前缀,最长的公共真前缀和真后缀长度,例如abcabc,next[1:6]={0,0,0,1,2,3}

    求next数组

    假设我们已经知道next[1:i-1],求next[i]。

    设last=next[i-1],则p[1:last]等于p[i-last:i-1],即模式串长度为i-1的前缀,前last个与后last个相同,且last最大,那么我们只需要检测p[i]与p[last+1]是否相等,相等就是last+1,否则要在这last个(p[i-last:i-1],即p[1:last])里面找,更新last=next[last],继续检测p[i]与p[last+1]是否相等,如此循环直到last=0,p[i]=p[1],即为1,否则为0。

    那么只需要设置next[1]=0,循环求即可。

    真正的KMP

    通过求next数组,我们发现:next数组的作用是当前面的匹配好了,而下一个匹配不到时,更新一个更小的来匹配,取代了重新匹配,来加速匹配。

    KMP的过程与求next的过程几乎完全相同。

    我们设last为匹配到T[i-1]时当前已经匹配的个数,即当last=strlen( P )时,匹配成功,现在求匹配T[i]时的last。

    我们已经匹配了last个,p[1:last]等于t[i-last:i-1](是不是很熟悉),如果p[i]与t[last+1]相同,last++,否则跳转到前面,last=next[last],尝试更小的匹配,直到完全不能匹配。

    代码

    作用:输出有多少次匹配,可重叠。

    由于通常的输入从0开始,这个代码的next数组从0到n-1,每一位比正常的next数组少1。

    回到开头的问题,如果想求的匹配不重叠,后面每当匹配到,last=0即可。

    #include<bits/stdc++.h>
    using namespace std;
    int n,last;
    char t[1000020],p[1002000];
    int nex[1002000];
    int main(){
    	scanf("%d",&n);
    	while(n--){
    		int ans=0;
    		scanf("%s%s",p,t);
    		int pl=strlen(p),tl=strlen(t);
    		nex[0]=last=-1;
    		for(int i=1;i<pl;i++){
    			while(last>-1&&p[i]!=p[last+1]){
    				last=nex[last];
    			}
    			if(p[i]==p[last+1]){
    				last++;
    			}
    			nex[i]=last;
    		}
    		last=-1;
    		for(int i=0;i<tl;i++){
    			while(last>-1&&t[i]!=p[last+1]){
    				last=nex[last];
    			}
    			if(t[i]==p[last+1]) last++; 
    			if(last+1==pl){
    				ans++;
    				last=nex[last];
    				//printf("%d
    ",i-pl+2);
    			}
    		}
    		/*for(int i=0;i<pl;i++){
    			//if(i!=0) printf(" "); 
    			//printf("%d",nex[i]);
    		}*/
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
    
    
  • 相关阅读:
    java实现DAG广度优先便利
    java实现图分组
    四。字符串
    二。链表
    一。数组
    TypeScript学习(六)@types包
    TypeScript学习(五)三斜线指令
    TypeScript学习(四)声明文件和declare关键字
    TypeScript学习(三)命名空间和模块
    TypeScript学习(二)函数重载
  • 原文地址:https://www.cnblogs.com/sz-wcc/p/11331357.html
Copyright © 2020-2023  润新知