题目传送门

解题思路:

首先说KMP的作用:对于两个字符串A,B(A.size() > B.size()),求B是否是A的一个字串或B在A里的位置或A里有几个B,说白了就是字符串匹配.

下面创设一个问题背景 : 有两个字符串A,B,求B在A中的位置.

A : abcdcbd

B: cdcb

对于上述问题,我们最先想到也就是最暴力的办法,就是把B整体从1~7每次一格的往右挪,每往挪一格,便把B从头到尾跟A匹配一遍,直到匹配不成功或全部匹配成功,如果匹配不成功,就再整体往右挪一格,这样的时间复杂度最坏可以达到O(nm).

如果字符串再长一点,长度达到1e6,显然暴力是会TLE的,那我们就要考虑优化,上述做法唯一能优化的地方就是往右挪的方式,因为一格一格的挪实在是太笨了,所以我们就要想怎样才能挪的快而且正确呢?

很容易想到的是1.直接移到B的后一位 2.移到失配的位置 ,而这两种做法都是可以被推翻的,见图:

那我们就只能甘于暴力吗?不,所以我们要学习KMP,进入正题:

对于学习KMP,要明白几个重要概念:

对于一个字符串A': abcddc

1.前缀:a,ab,abc,abcd,abcdd.

2.后缀:c,dc,ddc,cddc,bcddc.(前缀和后缀都不包括其本身)

然后我们来看一下KMP的伪代码:

 while(i < a.length() && j < b.length()) {
if(当前位置匹配) i++,j++;
else j = kmp[j]; //跳到一个特定的位置
}
if(j == b.length()) 成功
else 失败

看完后发现其实KMP的核心,就是求kmp[j](大多数人称为next[j]),下面就来说一下kmp[j]怎么求.

kmp[i]表示的是长度为i(1~i)的字符串的最长公共前后缀的长度.(以下的j皆为不包括本次字符求得的最长公共前后缀长度,其实也就是枚举前缀的长度)

例: P: a b c d a b c

kmp[]:0 0 0 0 1 2 3

求当前kmp[i],可以分两种情况:

1.当P[i] == P[j+1]时(见下图),kmp[i] = j+1,因为j=2说明P[1..2]和P[3..4]是完全相等的,而P[5]==P[3],那么P[1..3]和P[3..5]是完全相等的,那kmp[5] = 3;

2.当P[i] != P[j+1]时(见下图),j = kmp[j]往回跳,因为j == 3,说明P[1..3]和P[5..7]完全相等,而后缀的最后加上一个P[i],则意味着我们相当于在P[4]插入一个P[i],要在P[1..3]找一个位置j,使P[i] == P[j+1],转化为第一种情况,求kmp[4],即为kmp[i].那为什么j=kmp[j]呢,举个例子:aba插入一个b,只有两个a相等,后面才有可能成为公共前后缀.还有就是j要跳到什么程度呢?答案就是,当找到P[i]==P[j+1]时,或j跳到0了,说明不可能形成公共前后缀了,就停止.

下面上求kmp[]的代码:

 string l;
j = ;
kmp[] = ;
for(int i = ;i <= n; i++) {
while(j != && l[i] != l[j+]) j = kmp[j];
if(l[i] == l[j+]) j++;
kmp[i] = j;
}

然后,我们再回归问题,如何在A串中匹配B呢?Talk is cheap,show you the code.

 string a,b;
j = ;
kmp[] = ;
for(int i = ;i <= n; i++) {//n为B的长度
while(j != && b[i] != b[j+]) j = kmp[j];
if(b[i] == b[j+]) j++;
kmp[i] = j;
}
j = ;
for(int i = ;i <= m; i++) {//m为A的长度
while(j != && a[i] != b[j+]) j = kmp[j];//匹配失败就往回跳
if(a[i] == b[j+]) j++;//当前匹配成功
if(j == n) {//整个B匹配成功
printf("%d",i - j + );
return ;
}
}

最后说一点,就是对于A和B匹配的时候,并不是i在向后动,而是j在向前动.

最后的吐槽时间:这算法好难理解(自认为),想出这算法的三个人也太nb了,写这篇博客好累,虽然不一定有人看,但心里还是挺高兴的.

AC代码:

//洛谷题的AC代码

 #include<iostream>
#include<cstdio> using namespace std; string l1,l,pp,p2;
int lena,lenb,next[],j; int main() {
l1 = l = " ";
cin >> pp >> p2;
l += pp;l1 += p2;
lena = l.length();
lenb = l1.length();
next[] = ;
for(int i = ;i < lenb; i++) {
while(j != && l1[i] != l1[j+]) j = next[j];
if(l1[j+] == l1[i]) j++;
next[i] = j;
}
j = ;
for(int i = ;i < lena; i++) {
while(j != && l[i] != l1[j+]) j = next[j];
if(l[i] == l1[j+]) j++;
if(j == lenb - ) {
printf("%d\n",i - lenb + );
j = next[j];
}
}
for(int i = ;i < lenb; i++)
printf("%d ",next[i]);
return ;
}

KMP【模板】 && 洛谷 P3375的更多相关文章

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

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

  2. 洛谷 P3375 【模板】KMP字符串匹配 || HDU 1686 Oulipo || kmp

    HDU-1686 P3375 kmp介绍: http://www.matrix67.com/blog/archives/115 http://www.cnblogs.com/SYCstudio/p/7 ...

  3. 【数论】卢卡斯定理模板 洛谷P3807

    [数论]卢卡斯定理模板 洛谷P3807 >>>>题目 [题目] https://www.luogu.org/problemnew/show/P3807 [输入格式] 第一行一个 ...

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

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

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

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

  6. 洛谷 P3375 【模板】KMP字符串匹配 题解

    KMP模板,就不解释了 #include<iostream> #include<cstdio> #include<cstring> #include<algo ...

  7. 【模板】LIS模板 洛谷P1091 [NOIP2004提高组]合唱队形 [2017年4月计划 动态规划11]

    以题写模板. 写了两个:n^2版本与nlogn版本 P1091 合唱队形 题目描述 N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形. 合唱队形是指这样的一种队 ...

  8. 树链剖分模板(洛谷P3384)

    洛谷P3384 #include <bits/stdc++.h> #define DBG(x) cerr << #x << " = " < ...

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

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

随机推荐

  1. 「JSOI2014」强连通图

    「JSOI2014」强连通图 传送门 第一问很显然就是最大的强连通分量的大小. 对于第二问,我们先把原图进行缩点,得到 \(\text{DAG}\) 后,统计出入度为零的点的个数和出度为零的点的个数, ...

  2. spriteKit简单学习

    https://shimo.im/docs/YejitfPrGkcNO3Ls/ <SpriteKit学习相关> 关于SpriteKit   https://www.jianshu.com/ ...

  3. Chrome浏览器 HTML5看视频卡顿

    定位问题 起初以为是flash的问题,但是在B站看视频,由html播放改为flash播放后,卡顿现象消失 将相同的B站视频,用edge播放,也无卡顿现象 可以确定,问题出在chrome身上 解决方法 ...

  4. 用C/C++创建windows服务程序

    转载:https://blog.csdn.net/chenyujing1234/article/details/8023816 一.演示过程下方代码演示了如何使用vs(C/C++)创建windows服 ...

  5. 如何申请自己的Flag Counter?

    申请自己的Flag Counter是一件简单的事. 首先,进入Flag Counter主页. 之后,选择好样式,点击"GET YOUR FLAG COUNTER".会弹出一个对话窗 ...

  6. SRS源码——Listener

    1. 整理了一下Listener相关的UML类图:

  7. Java8 HashMap详解

    Java8 HashMap Java8 对 HashMap 进行了一些修改,最大的不同就是利用了红黑树,所以其由 数组+链表+红黑树 组成. 根据 Java7 HashMap 的介绍,我们知道,查找的 ...

  8. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 表格:将悬停的颜色应用在行或者单元格上

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  9. [网络必学]TCP/IP四层模型讲解【笔记整理通俗易懂版】

    OSI七层模型     表示层:用来解码不同的格式为机器语言,以及其他功能. 会话层:判断是否需要网络传输. 传输层:识别端口来指定服务器,如指定80端口的www服务. 网络层:提供逻辑地址选路,即发 ...

  10. Restful API及接口安全

    一.简介 REST(Representational State Transfer,具体状态转移),是一种基于HTTP协议.URI(统一资源定位符).JSON和XML这些现有协议与标准的,针对网络应用 ...