P3375 【模板】KMP

P3375 【模板】KMP

题目描述

给出两个字符串 s 1 s_1 s1 和 s 2 s_2 s2,若 s 1 s_1 s1 的区间 l , r l, r l,r 子串与 s 2 s_2 s2 完全相同,则称 s 2 s_2 s2 在 s 1 s_1 s1 中出现了,其出现位置为 l l l。

现在请你求出 s 2 s_2 s2 在 s 1 s_1 s1 中所有出现的位置。

定义一个字符串 s s s 的 border 为 s s s 的一个非 s s s 本身 的子串 t t t,满足 t t t 既是 s s s 的前缀,又是 s s s 的后缀。

对于 s 2 s_2 s2,你还需要求出对于其每个前缀 s ′ s' s′ 的最长 border t ′ t' t′ 的长度。

输入格式

第一行为一个字符串,即为 s 1 s_1 s1。

第二行为一个字符串,即为 s 2 s_2 s2。

输出格式

首先输出若干行,每行一个整数,按从小到大的顺序 输出 s 2 s_2 s2 在 s 1 s_1 s1 中出现的位置。

最后一行输出 ∣ s 2 ∣ |s_2| ∣s2∣ 个整数,第 i i i 个整数表示 s 2 s_2 s2 的长度为 i i i 的前缀的最长 border 长度。

输入输出样例 #1

输入 #1

复制代码
ABABABC
ABA

输出 #1

复制代码
1
3
0 0 1 

说明/提示

样例 1 解释

对于 s 2 s_2 s2 长度为 3 3 3 的前缀 ABA,字符串 A 既是其后缀也是其前缀,且是最长的,因此最长 border 长度为 1 1 1。

代码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+1;
int kmp[N];//所有子串的最长相同前后缀长度 
string s1,//文本串 
	s2;//模式串 
int main(){
	//freopen("data.cpp","r",stdin);
	cin>>s1>>s2;
	memset(kmp,0,sizeof(kmp));
	for(int i=1,j=0;i<s2.length();i++){
		while(j&&s2[i]!=s2[j])j=kmp[j];
		/*
		i长字符串后第一个字符,就是i位置字符s2[i]
		不等于
		i长字符串的最长相同前后缀j长子串后第一个字符,就是j位置字符s2[j]
		回溯
		找i长字符串的最长相同前后缀的最长相同前后缀 
		*/
		if(s2[i]==s2[j])j++;//如果相等,则最长相同前后缀要+1 
		kmp[i+1]=j;//i+1字符串的相同前后缀长是j 
	}
	for(int i=0,j=0;i<s1.length();){
		if(s1[i]==s2[j])i++,j++;//对齐了,各自找下一位 
		else if(j<s2.length())//没匹配 
		if(j>0)j=kmp[j];//模式串的对齐位置跳到j长字符串的最长相同前后缀后的第一个位置j 
		else i++;
		if(j==s2.length()){cout<<i-j+1<<endl;j=kmp[j];}//匹配后输出s2在i中的位置 
	}
	for(int i=0;i<s2.length();i++)cout<<kmp[i+1]<<" ";
	return 0;
}

小结

文本串的i位置和匹配串的j位置对齐。

相关推荐
Jerry2 小时前
LeetCode 28. 找出字符串中第一个匹配项的下标
算法
Jerry4 小时前
LeetCode 459. 重复的子字符串
算法
海石6 小时前
1500分的题目,确实有实力,不过还是我略胜一筹
算法·leetcode
海石6 小时前
【记忆化搜索】条条大路通AC,走好适合你的那一条,走到后再考虑走得快
算法·leetcode
Jerry8 小时前
LeetCode 151. 反转字符串中的单词
算法
a11177611 小时前
LM 算法迭代过程动画演示(SLAM)
算法
头茬韭菜11 小时前
Context 的生死抉择:四层压缩、截断算法与 Session Memory
算法·ai
Jerry11 小时前
LeetCode 541. 反转字符串 II
算法
Jerry11 小时前
LeetCode 344. 反转字符串
算法
搞科研的小刘选手12 小时前
【香港大学主办&IEEE出版】第六届计算机视觉、应用与算法国际学术会议(CVAA 2026)
算法·计算机视觉·应用·学术会议