ACW:831. KMP字符串
感觉这道题非常有意思,学的过程中觉得及难,学完之后觉得及简单,看y总的视频没有看懂。。。,因此自己找了一篇博文理解并完成题目。
import java.io.*;
/**
* @author admin
* @Date 2021/11/11 20:07
* @Description 思路主要参考: https://www.cnblogs.com/dusf/p/kmp.html ,
* 理解的前提为:明白如果abcdabce在e的时候匹配不成功不用从第0个a(为统一,下标从0开始)开始匹配,
* 而是直接从重复的abc后的一个元素d开始匹配即可,因为前后有重复的abc ,
* 假设已经知道e不匹配要跳回的元素是d的话(next数组),那么这就是一个不断匹配的过程
* 即:不成功就跳回到前一个重复的串的后一个元素,匹配。。。成功就跳回到前一个重复的串的后一个元素,匹配。。。一直重复下去
* 明白了这点下一步就是看跳回哪个下标,跳回的下标用next数组存放,因此next数组存放的就是:
* //next[k]表示的是第k个如果不匹配应该跳到哪个点,从第0个数开始----k点之前哦 ---也就是说第k点之前有多少个重复的!!!
* //比如a, b, c, a, b, d 对应的next数组为
* // -1, 0, 0, 0, 1, 2,
* //这样正好匹配当a不匹配时只能跳回第0个数a开始匹配,
* // 当b不能匹配时可以确保第二个a已经匹配,因此可以直接跳回第1个数(第0个b)开始匹配
* //也是因此第0个数不用判断(直接给-1,标识应该移动母串而不是子串了,因为第0个数都不匹配),最后一个数也是不用参与判断的(原因见上5行注释)
*
* 明白了上述过程后重点就是计算next数组,在计算next数组时候会发现一件事
* :kmp就是:比较字母串是否匹配, 不匹配就往next数组指定的下标跳
* :计算next数组就是: 比较当前字符串的后面与前面是否匹配 , 不匹配就?
* 应该已经有一些感觉了,不匹配就和比较的过程一样呗,往next数组指定的下标跳呗~!!!!!!!!!!最关键的点结束了
* (跳的时候不用太担心边界,是因为next数组存放的是一定是往前跳的,往后跳是不可能的)
* 这两个步骤就是重复的呀!!!!,而且最难理解的就在于k=next[k],即往前一个可以跳的地方跳再重新匹配这个过程
* 之后的一些细节应该不太难了
* @return
* @param
*/
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter BufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));
int n = Integer.parseInt(bufferedReader.readLine());
String s1 = bufferedReader.readLine();
int m = Integer.parseInt(bufferedReader.readLine());
String s2 = bufferedReader.readLine();
char[] p = s1.toCharArray();
char[] s = s2.toCharArray();
int[] next = ne(p);
//计算完ne数组下面计算的是kmp的输出
/*
这里的写法和求next数组基本一模一样,但是需要注意的是第0个数和最后一个数需要参与比较,
因此改动:1.j=-1开始,2.while (j <= s.length - 1)中的“=”;
然后由于求的是所有匹配结果,因此在匹配后加入特判k == p.length - 1,为true时
表示匹配成功,此时应该输出结果,以及当成此节点匹配失败重新开始匹配值(k = next[k];)
*/
int k = -1, j = -1;
while (j <= s.length - 1) {
if (k == -1 || s[j] == p[k]) {
if (k == p.length - 1) {
BufferedWriter.write(j - k + " ");
k = next[k];
continue;
}
k++;
j++;
}else {
k = next[k];
}
}
bufferedReader.close();
BufferedWriter.flush();
BufferedWriter.close();
}
private static int[] ne(char[] p) {
//next[k]表示的是k点之前有多少个重复的,从第0个数开始
//比如a, b, c, a, b, d 对应的next数组为
// -1, 0, 0, 0, 1, 2,
//这样正好匹配当a不匹配时只能跳回第0个数a开始匹配,
// 当b不能匹配时可以确保第二个a已经匹配,因此可以直接跳回第1个数(第0个b)开始匹配
//也是因此第0个数不用判断(直接给-1,标识应该移动母串而不是子串了,因为第0个数都不匹配),最后一个数也是不用参与判断的(原因见上5行注释)
int[] next = new int[p.length];
next[0] = -1;
int k = -1, j = 0;
while (j < p.length - 1) {
if (k == -1 || p[j] == p[k]) {
k++;
j++;
next[j] = k;
} else {
k = next[k];
}
}
return next;
}
}
ACW:831. KMP字符串的更多相关文章
- 831. KMP字符串(模板)
给定一个模式串S,以及一个模板串P,所有字符串中只包含大小写英文字母以及阿拉伯数字. 模板串P在模式串S中多次作为子串出现. 求出模板串P在模式串S中所有出现的位置的起始下标. 输入格式 第一行输入整 ...
- AcWing 831. KMP字符串(模板)
给定一个模式串S,以及一个模板串P,所有字符串中只包含大小写英文字母以及阿拉伯数字. 模板串P在模式串S中多次作为子串出现. 求出模板串P在模式串S中所有出现的位置的起始下标. 输入格式 第一行输入整 ...
- AcWing 831. KMP字符串
#include <iostream> using namespace std; , M = ; int n, m; int ne[N];//ne[i] : 以i为结尾的部分匹配的值 ch ...
- 831. KMP字符串
给定一个模式串S,以及一个模板串P,所有字符串中只包含大小写英文字母以及阿拉伯数字. 模板串P在模式串S中多次作为子串出现. 求出模板串P在模式串S中所有出现的位置的起始下标. 输入格式 第一行输入整 ...
- KMP字符串模式匹配详解(转)
来自CSDN A_B_C_ABC 网友 KMP字符串模式匹配通俗点说就是一种在一个字符串中定位另一个串的高效算法.简单匹配算法的时间复杂度为O(m*n);KMP匹配算法.可以证明它的时间复杂度 ...
- BM和KMP字符串匹配算法学习
BM和KMP字符串匹配算法学习 分类: 研究与学习 字符串匹配BM(Boyer-Moore)算法学习心得 http://www.cnblogs.com/a180285/archive/2011/12/ ...
- KMP字符串模式匹配详解(zz)
刚看到位兄弟也贴了份KMP算法说明,但本人觉得说的不是很详细,当初我在看这个算法的时候也看的头晕昏昏的,我贴的这份也是网上找的.且听详细分解: KMP字符串模式匹配详解 来自CSDN A_B_ ...
- KMP字符串模式匹配详解
KMP字符串模式匹配详解 http://www.cppblog.com/oosky/archive/2006/07/06/9486.html
- KMP字符串模式匹配学习笔记
KMP算法实验 1.编程计算模式串(子串)的next值.2.利用KMP算法在主串中找到模式串的位置. 参考代码:---------int getNexlVal( char * s, int j)// ...
随机推荐
- 人机交互大作业--flash嵌入web(纯界面)
界面: 源代码:最近较忙,后续会上传至github
- Java/C++实现模板方法模式---数据库操作
对数据库的操作一般包括连接.打开.使用.关闭等步骤,在数据库操作模板类中我们定义了connDB().openDB().useDB().closeDB()四个方法分别对应这四个步骤.对于不同类型的数据库 ...
- Android回到页面并刷新数据
通过对Android Activity的生命周期的了解,需要在后退页面重写onResume()的方法. 建立自己更新数据的函数,并在onCreate()方法中调用. @Override protect ...
- tracert命令简述
1. 路由跟踪在线Tracert工具说明 Tracert(跟踪路由)是路由跟踪实用程序,用于确定 IP 数据报访问目标所采取的路径.Tracert 命令用 IP 生存时间 (TTL) 字段和 ICMP ...
- centOS一次性更新所有依赖库
CentOS中使用yum一次性更新安装依赖库 [tom@localhost /]# sudo -s [root@localhost /]# LANG=C [root@localhost /]# yum ...
- What are PCIe Slots
https://www.hp.com/us-en/shop/tech-takes/what-are-pcie-slots-pc What are PCIe Slots and How Can I Us ...
- 谈谈.NET Core下如何利用 AsyncLocal 实现共享变量
前言 在Web 应用程序中,我们经常会遇到这样的场景,如用户信息,租户信息本次的请求过程中都是固定的,我们希望是这种信息在本次请求内,一次赋值,到处使用.本文就来探讨一下,如何在.NET Core 下 ...
- 【大话云原生】煮饺子与docker、kubernetes之间的关系
云原生的概念最近非常火爆,企业落地云原生的愿望也越发强烈.看过很多关于云原生的文章,要么云山雾罩,要么曲高和寡. 所以笔者就有了写<大话云原生>系列文章的想法,期望用最通俗.简单的语言说明 ...
- 关于IDEA中添加静态资源(html,jpg等)后找不到资源(404 not found),以及WEB-INF目录介绍
关于静态资源的加载 在IDEA中的java web application(或者maven项目)添加新的静态资源时(如html,jpg,gif等),常常会遇到静态资源无法加载的情况.这样的情况我们一般 ...
- Metalama简介4.使用Fabric操作项目或命名空间
使用基于Roslyn的编译时AOP框架来解决.NET项目的代码复用问题 Metalama简介1. 不止是一个.NET跨平台的编译时AOP框架 Metalama简介2.利用Aspect在编译时进行消除重 ...