2022-11-12 Acwing每日一题
本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的。同时也希望文章能够让你有所收获,与君共勉!
KMP字符串
给定一个字符串 S,以及一个模式串 P,所有字符串中只包含大小写英文字母以及阿拉伯数字。
模式串 P 在字符串 S 中多次作为子串出现。
求出模式串 P 在字符串 S 中所有出现的位置的起始下标。
输入格式
第一行输入整数 N,表示字符串 P 的长度。
第二行输入字符串 P。
第三行输入整数 M,表示字符串 S 的长度。
第四行输入字符串 S。
输出格式
共一行,输出所有出现位置的起始下标(下标从 0 开始计数),整数之间用空格隔开。
数据范围
1≤N≤105
1≤M≤106
输入样例:
3
aba
5
ababa
输出样例:
0 2
算法原理
如果需要得到一个字符串在另一个字符串中是否存在子串,以及子串的位置和个数的话,我们就可以使用KMP字符串匹配。
主要是通过由对于每一位最长的前后缀相等的子串的长度组成的next
数组进行优化,当我们碰到两个字符串p
和s
分别在j+1
和i
位上的字符不相同,我们可以通过在模式串p
的next
数组来寻找j
能回溯的最短距离,也就是他们匹配的最长距离。这样不仅保证对于s
的每一位我们都可以进行匹配,同时j也不会直接回溯到初始点,只要他们有相同的前后缀。
代码实现
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1000010;
char p[N],s[N];
int n,m;
int ne[N];
int main() /// KMP:找到目标串中的子串的下标,返回所有的下标
{
cin >> n >> p+1 >> m >> s + 1; // 从下标为1处开始存储字符串
for(int i=2,j=0 ; i<=n ; ++i){ // next数组只跟模式串p有关,所以两个指针都在p上一个是0(后面使用会+1),一个是2
while(j && p[i] != p[j+1]) j = ne[j]; // 如果不存在前后缀j=0,则退出,若存在前后缀且不匹配,则回溯
if(p[i] == p[j+1]) ++j; // 相等时才会++j,j=0时不会++j
ne[i] = j; // 第i位上的字符回溯位置一定是j
}
for(int i=1,j=0; i<=n; ++i){
while(j && s[i] != p[j+1]) j = ne[j]; // 在第j位上回溯
if(s[i] == p[j+1]) ++j;
if(j == n){
cout << i-n << ' ';
j = ne[j]; // 匹配成功可以回溯,也可以没有,在下一次循环时也会自动回溯的。
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】