mmxingye

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

16 | KMP 算法的典型应用(匹配位置、求出所有相同前缀后缀、最多字串重复次数)

记忆两段代码(注意字符串从下标为 1 开始存储)

  • 求 解 next 数组的代码
// 计算字符串 p 的next
for(int i=1,j=0;i<lenp;i++){
while(j&&p[i+1]!=p[j+1]) j=ne[j];
if(p[i+1]==p[j+1]) j++;
ne[i+1]=j;
}
  • 子串 匹配 代码
for(int i=0,j=0;i<lens;i++){
while(j&&s[i+1]!=p[j+1]) j=ne[j];
if(s[i+1]==p[j+1]) j++;
//判断匹配成功、
if(j==lenp){
//
}
}

🔧 字串位置

题目描述

给定一个父字符串s和子字符串p,请按照从前向后的顺序,请求出p在s中所有出现的起始位置。
例如:s = "ABADABCEABABA",p = "ABA",则求解的结果是:1 9 11。

输入

第1行读入一个仅包含大写字母的字符串s;
第2行读入一个仅包含大写字母的字符串p;
s和p均是长度不超过106的字符串。

输出

输出1行,按题意输出p在s中出现的位置,数字之间用空格隔开。

样例

输入

ABADABCEABABA
ABA

输出

1 9 11
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 +10;
char s[N],p[N];
int ne[N]; // ne[j] 代表 p 字符串 [1,j] 这个字串前缀和后缀相等的最长长度
int main(){
scanf("%s %s",s+1,p+1);
// 计算 next 数组的值
ne[0]=ne[1]=0;
int lens= strlen(s+1),lenp=strlen(p+1);
// 计算字符串 p 的next 值
for(int i=1,j=0;i<lenp;i++){
while(j&&p[i+1]!=p[j+1]) j=ne[j];
if(p[i+1]==p[j+1]) j++;
ne[i+1]=j;
}
// kmp 匹配
for(int i=0,j=0;i<lens;i++){
while(j&&s[i+1]!=p[j+1]) j=ne[j];
if(s[i+1]==p[j+1]) j++;
//判断匹配成功、
if(j==lenp){
printf("%d ",i+1-lenp+1); // 这个时候 i 还没有 +1 ,草稿纸画一下
}
}
return 0;
}

🔧最多字串重复次数

题目描述

给定若干个长度 ≤106 的字符串,询问每个字符串最多是由多少个相同的子字符串重复连接而成的。如:ababab 则最多有 3 个 ab 连接而成。

输入

输入若干行(所有行的字符串的长度之和≤107),每行有一个字符串,字符串仅含英语小写字母。特别的,字符串可能为 . 即一个半角句号,此时输入结束。

输出

对于每行输入,输出一个整数,代表计算的结果。

样例

输入

abcd
aaaa
ababab
.

输出

1
4
3

image-20220617190948632

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
char s[N];
int ne[N];
int main(){
while(scanf("%s",s+1) && s[1] != '.'){
//计算字符串s的next数组
ne[0] = ne[1] = 0;
int len = strlen(s+1);
//重新求解 ne 数组
for(int i = 1,j = 0;i < len;i++){
while(j && s[i+1] != s[j+1]) j = ne[j];
if(s[i+1] == s[j+1]) j++;
ne[i+1] = j;
}
//判断
if(len % (len - ne[len])== 0) printf("%d\n" ,len / (len-ne[len]));
else printf("%d\n",1);
}
return 0;
}

🔧 找到所有相等的前缀和后缀

题目描述

给定若干由小写字母组成的字符串(这些字符串总长 ≤4×105),在每个字符串中求出所有既是前缀又是后缀的子串长度。

例如:ababcababababcabab,既是前缀又是后缀的:ab,abab,ababcabab,ababcababababcabab。

输入

输入若干行,每行一个字符串。

输出

对于每个字符串,输出一行,包含若干个递增的整数,表示所有既是前缀又是后缀的子串长度。

样例

输入

ababcababababcabab
aaaaa

输出

2 4 9 18
1 2 3 4 5
#include <bits/stdc++.h>
using namespace std;
const int N=4e5+10;
char s[N];
int ne[N] ;
stack<int> st;
int main(){
while(scanf("%s" , s+1)!=EOF){
//计算字符串s的next数组
ne[0] = ne[1] = 0;
int len = strlen(s+1);
for(int i = 1,j = 0;i < len;i++){
while(j && s[i+1] != s[j+1]) j = ne[j];
if(s[i+1] == s[j+1]) j++;
ne[i+1] = j;
}
//len是必然可行的长度
st.push(len);
while(ne[len] != 0){
st.push(ne[len]);
len = ne[len];
}
//输出
while(!st.empty()){
printf("%d " ,st.top());
st.pop();
}
printf("\n");
}
return 0;
}

posted on   独立树  阅读(233)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示