题目描述

给出两个字符串 s_1s1​ 和 s_2s2​,若 s_1s1​ 的区间 [l, r][l,r] 子串与 s_2s2​ 完全相同,则称 s_2s2​ 在 s_1s1​ 中出现了,其出现位置为 ll。
现在请你求出 s_2s2​ 在 s_1s1​ 中所有出现的位置。

定义一个字符串 ss 的 border 为 ss 的一个非 ss 本身的子串 tt,满足 tt 既是 ss 的前缀,又是 ss 的后缀。
对于 s_2s2​,你还需要求出对于其每个前缀 s's′ 的最长 border t't′ 的长度。

输入格式

第一行为一个字符串,即为 s_1s1​。
第二行为一个字符串,即为 s_2s2​。

输出格式

首先输出若干行,每行一个整数,按从小到大的顺序输出 s_2s2​ 在 s_1s1​ 中出现的位置。
最后一行输出 |s_2|∣s2​∣ 个整数,第 ii 个整数表示 s_2s2​ 的长度为 ii 的前缀的最长 border 长度。

输入输出样例

输入 #1复制

ABABABC
ABA

输出 #1复制

1
3
0 0 1

说明/提示

样例 1 解释

对于 s_2s2​ 长度为 33 的前缀 ABA,字符串 A 既是其后缀也是其前缀,且是最长的,因此最长 border 长度为 11。

数据规模与约定

本题采用多测试点捆绑测试,共有 3 个子任务

  • Subtask 1(30 points):|s_1| \leq 15∣s1​∣≤15,|s_2| \leq 5∣s2​∣≤5。
  • Subtask 2(40 points):|s_1| \leq 10^4∣s1​∣≤104,|s_2| \leq 10^2∣s2​∣≤102。
  • Subtask 3(30 points):无特殊约定。

对于全部的测试点,保证 1 \leq |s_1|,|s_2| \leq 10^61≤∣s1​∣,∣s2​∣≤106,s_1, s_2s1​,s2​ 中均只含大写英文字母。

题目输出的第二部分不同于书上的next数组或nextval数组,题目要求输出的border意思是,到第i个字符时前后缀的相似度(前缀与后缀有一个长度的相同部分则border【i】=1这样子)。

大话数据结构上的next数组每个位置的值代表的是在当前字符前面的部分前后缀的相似度,而这道题我们要的是包括当前字符以及往前前后缀的相似度,那么我们可以加一个字符a(题目说s1​,s2​ 中均只含大写英文字母所以加一个小写字母不会影响判断),然后输出的值全部向后移动一位,即输出的循环这样写: for(int i=2; i<=l2+1; i++),并且当next【i】不等于0时,要将数据减一,因为k的值是这样来的:如果前后缀一个字符相等,则k=2,两个则k=3,n个则k=n+1。

刚开始写的代码一直ac70:

//ac70
#include<bits/stdc++.h>
using namespace std;char s[1100000],t[1100000];
int l1,l2;
int nextval[1100000];
int nextt[1100000];
//求模式串T的next函数修正值并存入数组nextvalvoid get_nextval()
{int i=1,k=0;nextval[1]=0;t[l2+1]='a';while(i < l2+1){if(k == 0||t[i] == t[k])//t[i]表示后缀的单个字符,t[k]表示前缀的单个字符{++i;++k;nextt[i]=k;if(t[i]!=t[k])nextval[i]=k;elsenextval[i]=nextval[k];}elsek=nextval[k];}
}void Index_KMP(int pos)
{int i=pos,j=1;get_nextval();//求到的模式串T的nextval值被存入next数组中while(i<=l1 && j<=l2){if(j == 0 || s[i] == t[j]){++i;++j;}else{j=nextval[j];}}if(j > l2)//如果文本串中都已经匹配到t了{cout<<i-l2<<endl;Index_KMP(i-1);}
}int main()
{scanf("%s%s",s+1,t+1);//从下标为1的位置开始存l1=strlen(s+1);//从下标为一的位置往后算元素个数l2=strlen(t+1);Index_KMP(1);for(int i=2; i<=l2+1; i++){if(nextt[i]!=0)cout<<nextt[i]-1<<" ";elsecout<<nextt[i]<<" ";}return 0;
}

错误的两个样例中我下载了一个查看  然后我发现问题在于这里的递归有问题。

该测试样例貌似是文本字符串为1000000个A,模板字符串为1000个A

当前面部分全部相同时,我的代码不能够接着下一个字符比对

然后我就把递归改成了Index_KMP(pos+1),但是我又发现这样子会导致部分样例重复查找到同一个相同部分的情况。

然后我发现转换next数组的方法过于冗杂,可以直接求出borad形式的“next数组”并在与文本字符串匹配时运用,相似度数组输出时能够直接正常输出无需改动后。

因为长度用l1和l2储存了也无需从下标为1开始存储,就直接输入字符串赋值给s和t即可。

那么按照相似的原理就要把 i=1;k=0:变成 i=0;k=-1;原本的next_[1]=0,改为next_[0]=-1,还有if判断中的k==0改为k==-1(都减了一!因为我们要让相似度值往前移动一位所以计算时也要把各个值往前移一位)其他部分无需改变。

void get_next()
{int i=0,k=-1;next_[0]=-1;while(i<l2){if(k==-1||t[i]==t[k]){++k;++i;nextval[i]=k;if(t[i]!=t[k])next_[i]=k;elsenext_[i]=next_[k];}elsek=next_[k];//若字符不同,则k值回溯}
}

匹配文本串的过程,每当匹配成功一段之后我们还得继续比对判断,这时我们要改变j的值可以避免之前那个代码遇到的问题

最终输出的相似度也无需做任何改变直接输出即可

(其中全局变量设置部分我也进行了改进,因为题目给出的数据范围为1000000,我们要设置多个数组,范围都在1000000以上,每次都写很麻烦,就可以宏定义一个M 1100000,方便程序编写和改动)

ac代码:

#include<bits/stdc++.h>
using namespace std;
#define M 1100000
char s[M],t[M];
int nextval[M];
int next_[M];//nextval的优化数组
int l1,l2;
void get_next()
{int i=0,k=-1;next_[0]=-1;while(i<l2){if(k==-1||t[i]==t[k]){++k;++i;nextval[i]=k;if(t[i]!=t[k])next_[i]=k;elsenext_[i]=next_[k];}elsek=next_[k];//若字符不同,则k值回溯}
}
void index_KMP()
{int i=0;int j=0;get_next();while(i<l1){if(j==-1||s[i]==t[j]){++i;++j;}elsej=next_[j];if(j==l2){printf("%d\n",i-l2+1);j=next_[j];//j值回溯到合适的位置}}
}
int main()
{cin>>s>>t;l1=strlen(s);l2=strlen(t);index_KMP();for(int i=1; i<=l2; i++)cout<<nextval[i]<<" ";return 0;
}

【模板】KMP字符串匹配相关推荐

  1. KMP算法小总结 洛谷P3375 【模板】KMP字符串匹配

    提问:这里有一个长度为n的字符串str1和长度为m的字符串str2(n > = m),问在str1中str2出现了几次? 如果使用暴力求解,一个一个比较,在n和m都极大的情况下将花费非常多的不必 ...

  2. 落谷 P3375 【模板】KMP字符串匹配

    题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next. 输入格式: 第一行为一个字符串,即为s1 ...

  3. Oulipo-欧力波(KMP字符串匹配问题)

    Oulipo-欧力波 HDU - 1686 The French author Georges Perec (1936–1982) once wrote a book, La disparition, ...

  4. Simpsons’ Hidden Talents辛普森一家的隐藏天赋(next数组和kmp字符串匹配)

    辛普森一家的隐藏天赋 HDU - 2594 目录 辛普森一家的隐藏天赋 HDU - 2594 题意描述:当给定字符串s1和s2时,找到s1中最长的前缀,即s2的后缀.如果有,输出相同的字符串即字符串长 ...

  5. KMP算法详解P3375 【模板】KMP字符串匹配题解

    KMP算法详解: KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt(雾)提出的. 对于字符串匹配问题(such as 问你在abababb中有多少个 ...

  6. 数据结构 kmp字符串匹配_用动画解释 KMP 算法

    大家好,我是一个每天在互联网都被读者催更催到爆肝,爆肾小鹿童鞋. 说实话,一些数据结构和算法我这辈子都不可能用到实际当中,但个人一直觉得能把复杂的东西讲明白是一件很牛逼的事情. 毕竟想牛逼也是很难的, ...

  7. Luogu3375 【模板】KMP字符串匹配

    复习字符串ing KMP模板 #include <iostream> #include <cstdio> #include <cstring> #include & ...

  8. 洛谷 P3375 【模板】KMP字符串匹配

    我这段时间因为字符串太差而被关了起来了(昨晚打cf不会处理字符串现场找大佬模板瞎搞,差点就凉了),所以决定好好补一下字符串的知识QAQ,暂时先学习kmp算法吧~ 题目链接:https://www.lu ...

  9. 【luogu 3375】【模板】KMP字符串匹配

    题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next. (如果你不知道这是什么意思也不要问,去百度 ...

最新文章

  1. caffe中在某一层获得迭代次数的方法以及caffe编译时报错 error: ‘to_string‘ is not a member of ‘std‘解决方法
  2. 等价类、边界值的概念及划分
  3. 计算机组成原理(分析计算题解析)内附填空,选择,解答题答案
  4. 2D空间中基于矢量运算的碰撞后效果as3源码
  5. 少儿编程100讲轻松学python(十一)-python如何保留小数点位数
  6. vue项目接口地址暴露_vue组件暴露和.js文件暴露接口操作
  7. 你的main函数规范吗?
  8. python 标签字体大小_Python玩转Excel(第3期)~这里只有干货
  9. Open***+ldap配置过程
  10. 爬虫之 单线程+多任务异步协程
  11. 帆软连接数据库的步骤
  12. cpe动态ip,做端口映射方案
  13. 辽宁民办计算机学校排名2015,2021辽宁民办大学排名 最新高校排行榜
  14. C语言,枚举法求两个数的最大公约数
  15. 从xgboost, lightgbm 到catboost
  16. 陌陌和它的解药,聊聊出海社交产品的思路
  17. 基于内存搜索的进程检测方法
  18. 树莓派初次开机配置教程
  19. 滴滴客服解决方案平台建设实践
  20. Clonezilla再生龙备份与还原linux系统

热门文章

  1. mysql 南邮ctf_南邮ctf之web之wp
  2. python 菜鸟联盟快递查询_快递单号查询接口-极兔速递
  3. MATLAB自动驾驶学习(4)交通路口仿真测试
  4. cookie、session、token、webStorage的关系与区别
  5. 软件开发中的一些风险控制
  6. 3星|《工作是最好的修行》:樊登读书会节目文稿,14篇读书笔记
  7. java redis的同步_java同步系列之redis分布式锁进化史
  8. 存货核算凭证无法删除的修复 U8 10.1存货核算中的凭证列表显示时,部分凭证会分两行显示,且不能删除...
  9. Pi利用爬虫打造专属语音闹钟
  10. 声学机器学习:理论和应用 (Machine learning in acoustics: Theory and applications)