首页 > 其他分享 >P3375 【模板】KMP( 普及/提高− ) 题解

P3375 【模板】KMP( 普及/提高− ) 题解

时间:2023-11-27 19:16:08浏览次数:39  
标签:匹配 int 题解 KMP next 算法 kmp P3375 失配

题目传送门

思路:

首先我们要学习一下 \(KMP\) 算法,不会的可以看这个大佬的文章

那么我们就直接开始讲思路了。
针对于每一位,\(kmp\) 算法已经预处理出了一个对应 \(kmp\) 数组的单元,映射着如果此位失配,它可能的最靠后的一个重新开头是哪一个。
让我们举一个例子:假如让 \(aaab\) 与 \(aab\) 匹配。一开始,\(aab\) 的 \(aa\) 与 \(aaab\) 的开始的 \(aa\) 成功匹配,但到了第三位失配了。此时,朴素算法会跳出,找到下一个开头进行比对。然而 \(kmp\) 算法用 \(next\) 数组得知,这位失配后应该可能却可以与第二位匹配成功,而又成功,于是又继续往后匹配,然后就匹配成功了,只比较了 \(5\) 次,比 \(O(n^2)\) 好了不少。

时间复杂度:\(O(m+n)\)

注意了

此题有坑。
喜欢直接用算法中的名称定义数组的要小心了。
在 \(windows\) 操作系统中的

int next[];

是没有问题的。
但是,在 \(Linux\) 系统中,\(next\) 是一个系统函数。
所以,在使用 \(Linux\) 系统的评测机中定义一个叫 \(next\) 的容器,会 \(CE\),也就是编译错误。
ps:这可是我十几次 \(CE\) 的血汗教训啊!

next表实现模板

//用string类型也可以
char a[1000010]; // 文本串
char b[1000010]; // 模板串(将被匹配的子串)
int kmp_next[1000010]; // next数组
void getNext(int m){
	int j = 0;
	// 初始化next[0]的值
	kmp_next[0] = 0;
	for(int i=1; i<m; ++i){
		// 当这一位不匹配时,将j指向此位之前最大公共前后缀的位置
		while(j>0 && b[i]!=b[j]) j=kmp_next[j-1];
		// 如果这一位匹配,那么将j+1,继续判断下一位
		if(b[i]==b[j]) ++j;
		// 更新next[i]的值
		kmp_next[i] = j;
	}
}

Code:

#include <bits/stdc++.h>
using namespace std;
char a1[2000005],a2[2000005];
int kmp[2000005];
int main()
{
	scanf("%s%s",a1,a2);
	kmp[0]=kmp[1]=0;//前一位,两位失配了,都只可能将第一位作为新的开头
	int len1=strlen(a1),len2=strlen(a2);
	int k;
	k=0;
	for(int i=1;i<len2;i++)//自己匹配自己
	{
		while(k&&a2[i]!=a2[k])
		{
			k=kmp[k];//找到最长的前后缀重叠长度
		}
		kmp[i+1]=a2[i]==a2[k]?++k:0;//不相等的情况,即无前缀能与后缀重叠,直接赋值位0(注意是给下一位,因为匹配的是下一位适失配的情况)
	}
	k=0;
	for(int i=0;i<len1;i++)
	{
		while(k&&a1[i]!=a2[k])
		{
			k=kmp[k];//如果不匹配,则将利用kmp数组往回跳
		}
		k+=a1[i]==a2[k]?1:0;//如果相等了,则匹配下一位
		if(k==len2)
		{
			printf("%d\n",i-len2+2);//如果已经全部匹配完毕,则输出初始位置
		}
	}
	for(int i=1;i<=len2;i++)
	{
		printf("%d ",kmp[i]);//输出f数组
	}
	return 0;
}

标签:匹配,int,题解,KMP,next,算法,kmp,P3375,失配
From: https://www.cnblogs.com/BadBadBad/p/P3375.html

相关文章

  • P9447 [ICPC2021 WF] Spider Walk 题解
    更好的阅读体验很有意思的一道题。设\(f_i\)表示第\(i\)根线的答案,首先有一个关键结论:任意两根相邻的线答案只差一定小于\(1\)。原因显然,可以在无限远的地方加一根线来构造。该结论可以扩展一下,对于距离为\(d\)的两根线,答案之差不会超过\(d\)。考虑进行倒着加线,考虑加......
  • CF1900 C Anji's Binary Tree 题解
    LinkCF1900CAnji'sBinaryTreeQuestion给出一个树,每个节点上有一个字母L/R/U,从\(1\)号根节点开始,L表示接下来走到左节点,R表示接下来走到右节点,U表示接下载走到父节点问,最少修改几个节点上的字母使得从根节点走到叶子节点Solution定义\(F_x\)表示从\(x\)走到叶......
  • P7626 [COCI2011-2012#1] MATRIX( 普及/提高− ) 题解
    题目传送门思路:首先思考暴力,\(O(n^4)\)的时间复杂度,不行。那么我们这里就要运用到一点前缀和的知识了。我们可以用前缀和对两条对角线进行计数。每个点有两个对角线运算。差不多是\(O(n^2)\)到\(O(n^3)\)的时间复杂度。而\(n\leq400\)稳过。Code:#include<bits/stdc......
  • 复旦大学数学学院23级高等代数I期中考试精选大题解答
    四、求解下列线性方程组,其中$a_1,\cdots,a_n,b$为参数且$\sum\limits_{i=1}^na_i\neq0$:$$\begin{cases} (a_1+b)x_1+a_2x_2+a_3x_3+\cdots+a_nx_n=0,\\ a_1x_1+(a_2+b)x_2+a_3x_3+\cdots+a_nx_n=0,\\ a_1x_1+a_2x_2+(a_3+b)x_3+\cdots+a_nx_n=0,\\ \hfill\cdots\cdots......
  • CF1900 B Laura and Operations 题解
    LinkCF1900BLauraandOperationsQuestion给出\(1,2,3\)的个数\(a,b,c\)可以分别减少两个不同的数,增加一个与两个数都不同的数问,是否能经过一些操作使得就剩下\(1\)或\(2\)或\(3\)Solution先考虑\(1,2,3\)其实是等价的,所以我们只需要考虑把\(2,3\)全都变成......
  • CF1900 A Cover in Water 题解
    LinkCF1900ACoverinWaterQuestion给出一个\(n\)个格子,有些格子被堵塞了,有些格子是空的,我需要在进行一些操作,使得所有空的格子里面都有水操作1:给任意一个格子装上水操作2:把一格水从一个地方搬运到另外一个空的格子里如果一个空的格子的相邻的两个格子都有水,那么这......
  • Live Server插件打开浏览器时:该网页无法正常运作,127.0.0.1未发送任何数据的问题解决
    一、问题复现今天使用VsCode写HTML代码时,使用LiveServer打开预览时,发现浏览器显示“该网页无法正常运作,127.0.0.1未发送任何数据”的问题。二、解决办法1.在左侧工具栏找到扩展商店,找到LiveServer,然后点击对应的小齿轮,进入插件设置。2.选择ExtensionSettings3.进入......
  • KMP算法
    #include<iostream>usingnamespacestd;int*getNext(stringpattern){int*next=(int*)malloc(sizeof(int)*pattern.size());if(next==NULL){returnNULL;}next[0]=-1;intj=-1;for(inti=1;i<p......
  • ABC330 A-E 题解
    ABC330题解AtCoderBeginnerContest330A-CountingPasses思路:枚举一遍,当前数大于\(L\)使\(ans+1\)即可.代码:#include<iostream>#defineintlonglongusingnamespacestd; intn,l,ans;intx; signedmain(){ cin>>n>>l; for(inti=1;i&......
  • Information Graph 题解
    题目链接InformationGraph分析在线并不好做,考虑离线,先将树建出来\(2\)操作时\(x\)节点与当前根节点之间的点都会获得文件当前根节点可以用并查集维护对于查询的节点判断它是否为链上的点即可具体的,若该节点为\(rt\)子树中的点且该节点的子树包含\(x\)节点,它就......