蒟蒻对KMP的浅显理解

KMP算法是一种用于在目标字符串S中高效查找模板串T的算法,避免了暴力匹配在大数据规模下的TLE问题。关键在于lo数组,存储每个位置的最大相等前缀与后缀长度,用于不匹配时的回溯,提高效率。通过理解lo数组,能更好地掌握KMP算法的工作原理。
摘要由CSDN通过智能技术生成

KMP算法的用途

KMP算法常常用于在一个目标字符串S中找到模板串T的位置,我们平常碰到这种匹配问题,可能最先想到的就是暴力匹配。这种方法对于数据规模不大的时候是较为有效的,但是在数据规模比较大的情况下,往往会造成TLE。那么该怎么办呢?这时候我们就可以请出我们的KMP算法了。KMP算法在牺牲了一些空间的条件下,却大大的提升了我们的时间效率,经典的“以空间换时间”(优势在我)。

KMP算法的理解

事实上KMP算法的代码量并没有多大,但是这个算法极其诡异,令人匪夷所思。
先贴上代码

ll n,k,t;
char p[maxn];
char s[maxn];
int lo[maxn];
void solve()
{
cin>>n>>p+1>>k>>s+1;
for(int i=2,j=0;i<=n;i++)
{
	while(j&&p[i]!=p[j+1]) 
	{
		j=lo[j];
	}
	if(p[i]==p[j+1])
	{
		j++;
	}
	lo[i]=j;
}
for(int i=1,j=0;i<=k;i++)
{
	while(j&&s[i]!=p[j+1])
	{
		j=lo[j];
	}
	if(s[i]==p[j+1])
	{
		j++;
	}
	if(j==n)
	{
		cout<<i-n+1<<endl;
		j=lo[i];
	}
}
} 

事实上,这个算法里面最为重要的是搞清楚lo数组存的是什么,将它搞懂,我们对于这个算法的理解将变得较为容易许多。

事实上,这个lo数组存的是模板串里面第i个字符的(相等的最大前缀与最大后缀)。例子如下
假设我们的目标串为S,模板串为P
S=“abababc"
P=“abab”
其中lo[1]=0,由于1前面没有字符,所以事实上lo数组的确定是从2开始的。
lo[2]=0,其中我们前缀和后缀的长度不得大于当前位置i,这里的前缀为a,后缀为b,不相等。所以为0.
lo[3]=1,其中前缀={“a”,“ab”"},后缀={“a”,“ba”},这里相等的最大长度为1.
lo[4]=2,其中前缀={“a”,“ab”,“aba”},后缀={“b”,“ab”,“bab”},这里相等的最大长度为2。

所以看到了吧,这个lo数组存的就是这么一个东西。

好,现在我们就来探究这个是什么作用,这个也是该算法最主要的

j=lo[j];

令S=“babaca”,T=“babab”;
当i=5时,S[i]=‘c’,T[i]=‘b’,这里产生不匹配。
由于我们此时匹配的字符串长度为4,所以我们此时要进行回溯,将模板串指针j的位置从4调整到2,因为在前四个字符中,最大前缀与相等的最大后缀为2。

如此调整的理由如下:

虽然在5处未匹配,但是这也说明了目标串在该段之前的4个字符是与我们的模板串匹配的,而且前四个字符串的最大相等前缀和后缀为2,所以我们可以将j移动到2的位置,从此处开始进行匹配。这样我们就略过了前面的检验,节省了时间。

由于是刚开始写博客,所以写的很烂,如果有想更好了解该算法的,可以参考这篇
KMP 算法详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值