拓展 KMP 学习

初识扩展 KMP , 看了挺久的。可以参考这篇博客 和 第二篇

给定两个字符串 S , T (序列),求( S 的所有后缀 )和 T 的最长前缀。

例如 S 是  abcde

求 abcde 和 T 的最长前缀

求 bcde 和 T 的最长前缀

求 cde 和 T 的最长前缀

求 de 和 T 的最长前缀

求 e 和 T 的最长前缀

如果最长前缀长度  =  T.length() ,就是 KMP 了。

我个人脑海里抽象的 KMP 就如下图所示:


如果我知道了 p 处的S后缀和 T 的最长前缀是  extend[p] , 要求 i 处S的后缀和 T 的最长前缀。

可以发现 , 从 [ p , p+extend[p] ] 和 T  的 [ 0 , extend[p] ] 是一模一样的,如果  i 处在 这段相同的内部,就可以得出 1 和  2 是一样的,然后,我利用类似 KMP 的“一头一尾”前缀后缀,就可以得出  2 和 3 有一部分(next[i-p])是一样的, 这样就可以让从 i 处开始的S后缀,直接跳 " next[i-p] " 个距离,再继续匹配。

的确很抽象,整体就是  1 == 2 , 根据 T  自身的KMP , 找出 2 和 3 相同的部分 ,最终 S 直接 从 i+ next[i-p] 之后开始匹配

这样就可以省去一部分的匹配,T 从 next[i-p] 之后继续匹配。

然后就是一些分类了,分类可以参考这篇博客 https://www.61mon.com/index.php/archives/186/

#include <bits/stdc++.h>
using namespace std ;
const int N = 1000005 ;
char S[N<<1|1] , T[N] ;
int next[N] , extend[N<<1|1] ;
int begin ;

void Extend_KMP( char *S , char *T , int *extend , int *next ){
	int n = strlen( S ) , m = strlen( T ) ;
	int p = 0 , mx = 0 ;
	for( int i = begin ; i < n ; ++i ){
		if( i + next[i - p] < mx )         // mx = p + extend[p] 是最远的右端
			extend[i] = next[i - p] ;
		else{
			int j = max( 0 , mx - i ) ;
			while( i+j < n && j < m && S[i + j] == T[j] )
				++j ;
			mx = ( p = i ) + ( extend[i] = j ) ;
		}
	}
}

int main(){
	while( ~scanf( "%s%s" , S , T ) ){
		cout << S << endl << T << endl ;
	    next[0] = strlen( T ) ;
		begin = 1 ;
		Extend_KMP( T , T , next , next ) ;
		begin = 0 ;
		Extend_KMP( S , T , extend , next ) ;
	}
	return 0 ;
}

如果代码有错,敬请指正。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值