前言:

额……很久以前就写了KMP模板(只是半知不解),话说看完了manacher,再回过头看KMP,是真TM简单啊!字符串专题整体较抽象,所以必须牢记思路并时常复习

题目描述

如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置。

为了减少骗分的情况,接下来还要输出子串的前缀数组next。

(如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了。)

输入输出格式

输入格式:

第一行为一个字符串,即为s1

第二行为一个字符串,即为s2

输出格式:

若干行,每行包含一个整数,表示s2在s1中出现的位置

接下来1行,包括length(s2)个整数,表示前缀数组next[i]的值。

输入输出样例

输入样例#1:

ABABABC
ABA
输出样例#1:

1
3
0 0 1

说明

时空限制:1000ms,128M

数据规模:

设s1长度为N,s2长度为M

对于30%的数据:N<=15,M<=5

对于70%的数据:N<=10000,M<=100

对于100%的数据:N<=1000000,M<=1000000

样例说明:

所以两个匹配位置为1和3,输出1、3

Solution: 

什么是字符串匹配:

  简单来讲,就是给定两个字符串,判断长度较短的字符串是否是长字符串的子串,并输出第一次出现的位置。

暴力解法:

  用两个下标分别表示当前匹配到的主串和模式串的位置,每次移动主串和模式串的下标并匹配,不匹配时主串回到上个下标的后一个位置,模式串从头开始匹配,不停进行直到模式串下标越界说明匹配成功。这样暴力的复杂度是$O(mn)$,比如(主串:aaaaaaaaab  模式串:ab  暴力匹配显然要在主串上移动下标$n$次且每次模式串移动下标$m$次)

kmp的作用:

  我们从暴力解法中,容易看出每次匹配失败后,主串下标的移动和模式串下标的重置使得效率变低。而$KMP$能避免多余的下标移动,使得主串下标每次不回退,模式串直接从上次失配的位置开始匹配,这样使复杂度变成$O(m+n)$。

具体思想:

  我们预处理出模式串的从头开始的各子串的最长公共前后缀,当模式串在某一位置失配时,直接将模式串移动到已经匹配的模式串子串的最长公共前后缀的位置并使他们重叠,这样便能防止不必要的移动减损效率。

  而预处理$next$数组时,实际上就是一个线性的$dp$,因为我们发现每增加$1$个字符,最长公共前后缀的改变会和前面处理出的$next$有关,举个例子:aba 的最长公共前后缀为$1$,当变为abab时,只需判断新增的b和开始的第$1+1$个字符是否相同。这样就是一个线性递推的过程,但是具体实现时有一些细节,举举例子就能知道了。

  讲的不够清楚,网上的博客还行,可以去$B$站看下这个视频

代码:

#include<bits/stdc++.h>
#define il inline
#define ll long long
using namespace std;
int next[],m,n;
char s1[],s2[];
il void getnext(char *s2){
for(int i=;i<m;i++){
int j=i;
while(j){
j=next[j];
if(s2[j]==s2[i]){next[i+]=j+;break;}
}
}
}
int main()
{
scanf("%s%s",s1,s2);
n=strlen(s1),m=strlen(s2);
getnext(s2);
int j=;
for(int i=;i<n;i++){
while(j&&s1[i]!=s2[j])j=next[j];
j+=s1[i]==s2[j]?:;
if(j==m)printf("%d\n",i-m+);
}
for(int i=;i<=m;i++)printf("%d ",next[i]);
return ;
}

P3375【模板】KMP字符串匹配的更多相关文章

  1. P3375 模板 KMP字符串匹配

    P3375 [模板]KMP字符串匹配 来一道模板题,直接上代码. #include <bits/stdc++.h> using namespace std; typedef long lo ...

  2. 洛谷P3375 [模板]KMP字符串匹配

    To 洛谷.3375 KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果 ...

  3. 算法模板——KMP字符串匹配

    功能:输入一个原串,再输入N个待匹配串,在待匹配串中找出全部原串的起始位置 原理:KMP算法,其实这个东西已经包含了AC自动机的思想(fail指针/数组),只不过适用于单模板匹配,不过值得一提的是在单 ...

  4. [模板]KMP字符串匹配

    洛谷P3375 注意:两次过程大致相同,故要熟读熟记,切勿搞混 可以看看其他的教程:http://www.cnblogs.com/c-cloud/p/3224788.html 本来就不太熟,若是在记不 ...

  5. [模板] KMP字符串匹配标准代码

    之前借鉴了某个模板的代码.我个人认为这份代码写得很好.值得一背. #include<bits/stdc++.h> using namespace std; const int N=1000 ...

  6. P3375 【模板】KMP字符串匹配

    P3375 [模板]KMP字符串匹配 https://www.luogu.org/problemnew/show/P3375 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在 ...

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

    P3375 [模板]KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next. (如 ...

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

    KMP字符串匹配 模板 洛谷 P3375 题意 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.(如果 ...

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

    原题链接 Description 模板题啦~ Code //[模板]KMP字符串匹配 #include <cstdio> #include <cstring> int cons ...

  10. Luogu 3375 【模板】KMP字符串匹配(KMP算法)

    Luogu 3375 [模板]KMP字符串匹配(KMP算法) Description 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来 ...

随机推荐

  1. dedecms左侧导航栏不显示问题

    dedecms左侧导航栏不显示问题 在做织梦项目时,经常会碰到后台左侧导航栏不显示的问题,如下所示: ​ 这主要是由于文件权限不足造成的.有两种方法 第一种:把 /data 文件夹全部改成 777 权 ...

  2. ZooKeeper(2)-安装和配置

    一.下载 https://zookeeper.apache.org/ 二.本地模式安装 1.安装前准备 (1)安装Jdk (2)拷贝Zookeeper安装包到Linux系统下 (3)解压到指定目录 . ...

  3. 自己动手编写 Dockerfile 构建自定义的Jenkins

    1.构建jenkins 镜像 vim Dockerfile FROM jenkins  USER root ARG dockerGid=999  RUN echo "docker:x:${d ...

  4. 【Markdown】Markdown的使用(自用)

    # 欢迎使用 Cmd Markdown 编辑阅读器 我们理解您需要更便捷更高效的工具记录思想,整理笔记.知识,并将其中承载的价值传播给他人,Cmd Markdown 是我们给出的答案 -- 我们为记录 ...

  5. 【struts2】struts2的使用

    1.使用步骤 1) 导入struts2的支持jar包 名称 说明 struts2-core-2.3.4.1.jar Structs2的核心类库 xwork-core-2.3.4.1.jar xwork ...

  6. 008---re正则模块

    re正则模块 字符串的匹配规则 匹配模式 re.match() re.search() re.findall() re.split() re.sub() 元字符 print('------------ ...

  7. python2.7练习小例子(二十二)

        22):题目:有一分数序列:2/1,3/2,5/3,8/5,13/8,21/13...求出这个数列的前20项之和.     程序分析:请抓住分子与分母的变化规律. #!/usr/bin/pyt ...

  8. c/c++ 随机数生成

    当程序需要一个随机数时有两种情况下使用: 1.程序中只需使用一次随机数,则调用rand()函数即可 2.程序需要多次使用随机数,那么需要使用srand()函数生成随机数种子在调用rand()函数保证每 ...

  9. 1698-Just a Hook 线段树(区间替换)

    Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  10. allegro导入网表过程中出现的错误信息

    1. 找不到焊盘PAD,下面这句话的意思是器件封装找不到焊盘46.pad WARNING(SPMHNI-): Unable to load symbol ): Could not find padst ...