引言

众所周知,字符串无论是在 OI 中还是别的计算机领域都占有比较大的比重,今天说的就是一个关于匹配字符串的算法——「 KMP 算法 」。

0x00

KMP 算法用于解决这样的一类问题:给定一个文本串 T 和模式串 S,要求你求出 S 在 T 中出现的次数和位置(我们定义位置为 S 中第一个字符在 T 中匹配到的位置)

当然它还有许多别的用法。具体的可以通过一道题目来体现一下 HDU 3336

0x01

我们都知道朴素的匹配字符串的算法,不知道的看下面这个例子。

  1. 文本串:ABADCADCAB
  2. 模式串:ADCAB
  1. A 和 A 匹配,比较下一位。一直到发现 B 和 D 不匹配。
  2. 不匹配就将模式串后移一位。
  3. A 和 B 不匹配,重复之前的过程直到匹配完成。

但是我们发现下面这种情况

  1. ABABCADCAB
  2.   ADCAB

最后一位 B 和 D 并不能匹配。但是按照朴素算法的话会将模式串一位一位的往后移动。

直到出现下面的情况

  1. ABABCADCAB
  2.      ADCAB

试想,如果在第五位失配后我们可以直接将模式串的第一位直接移动到第四位。

虽然我们能够看出这样很简单,但如何让计算机也看出来呢?

这里我们引入一个 $next$ 数组,通俗的说,$next[i]$ 含义就是长度为 $i$ 的模式串前缀的前缀和后缀所共有的最长的字串。

我们先不说 $next$ 数组怎样求,先来说说它怎么用。

是不是很绕口呢

我们看看这句话是啥意思

  1. 模式串:ADCAB
  2. 前缀:A,AD,ADC,ADCA
  3. 后缀:B,AB,CAB,DCAB

上面这个就是在一个长度为 $5$ 的前缀中所有的前缀和后缀

我们看这些前后缀中有哪些是满足有共同的元素的

只有下面这两个

  1. AD,AB

它们返回的 $next$ 值是 $1$,也就是说在第五位失配之后,第一位就会跳到第四位去继续匹配。

0x02

这个 next 数组怎么求出来的。

我们试图让模式串自己匹配自己。

说到这里大概就知道为什么之前不告诉大家怎么求 $next$ 数组了吧?

因为这个 $next$ 数组会用了就会求了。而两者相比的话,「 用 」这一方面比较简单好理解

看下面这个求 $next$ 数组的代码。

  1. inline void Getnext() {
  2. for(int i=; i<=n; i++) {
  3. p = nxt[i-];
  4. //i的前一位在失配后哪一位会跳过来
  5. while(p && s[p+] != s[i]) p = nxt[p];
  6. //如果next[i]这一位还是不能和s[i]匹配,那就继续往前跳
  7. //这句话中p!=0表示如果跳到第一位就可以不用跳了
  8. if(s[p+] == s[i]) nxt[i] = p+;
  9. //如果找到了能够匹配的,就更新next[i]
  10. else nxt[i] = ;
  11. //找不到就是0
  12. }
  13. }

下面贴一下完整的代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. const int maxn = 1e6+;
  5. using namespace std;
  6. int n, m, next[maxn], p;
  7. char T[maxn], S[maxn];
  8. inline void Getnext() {
  9. for(int i=; i<=n; i++) {
  10. p = next[i-];
  11. while(p && s[p+] != s[i]) p = next[p];
  12. if(s[p+] == s[i]) next[i] = p+;
  13. else next[i] = ;
  14. }
  15. }
  16. int main() {
  17. scanf("%s%s", T+, S+);
  18. n = strlen(T+), m = strlen(S+);
  19. Getnx();
  20. p = ;
  21. for(int i=; i<=n; i++) {
  22. while (p && T[i] != S[p+]) p = next[p];
  23. if(T[i] == S[p+]) p++;
  24. else p = ;
  25. if(p == m) printf("%d\n", i-m+), p = next[p];
  26. }
  27. for(int i=; i<=m; i++) {
  28. printf("%d ", next[i]);
  29. }
  30. }

字符串匹配「 KMP 算法 」的更多相关文章

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

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

  2. 字符串匹配的 KMP算法

    一般字符串匹配过程 KMP算法是字符串匹配算法的一种改进版,一般的字符串匹配算法是:从主串(目标字符串)和模式串(待匹配字符串)的第一个字符开始比较,如果相等则继续匹配下一个字符, 如果不相等则从主串 ...

  3. 字符串匹配的kmp算法 及 python实现

    一:背景 给定一个主串(以 S 代替)和模式串(以 P 代替),要求找出 P 在 S 中出现的位置,此即串的模式匹配问题. Knuth-Morris-Pratt 算法(简称 KMP)是解决这一问题的常 ...

  4. HDU 1711 Number Sequence (字符串匹配,KMP算法)

    HDU 1711 Number Sequence (字符串匹配,KMP算法) Description Given two sequences of numbers : a1, a2, ...... , ...

  5. 字符串匹配(KMP 算法 含代码)

    主要是针对字符串的匹配算法进行解说 有关字符串的基本知识 传统的串匹配法 模式匹配的一种改进算法KMP算法 网上一比較易懂的解说 小样例 1计算next 2计算nextval 代码 有关字符串的基本知 ...

  6. 实现字符串匹配的KMP算法

    KMP算法是Knuth-Morris-Pratt算法的简称,它主要用于解决在一个长字符串S中匹配一个较短字符串s. 首先我们从整体来把我这个算法的思想. 字符串匹配的朴素算法: 我们容易想到朴素算法, ...

  7. 字符串匹配的KMP算法

    ~~~摘录 来源:阮一峰~~~ 字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串”BBC ABCDAB ABCDABCDABDE”,我想知道,里面是否包含另一个字符串”ABCDABD”? 许 ...

  8. 字符串匹配的KMP算法详解及C#实现

    字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD" ...

  9. 字符串匹配与KMP算法实现

    >>字符串匹配问题 字符串匹配问题即在匹配串中寻找模式串是否出现, 首先想到的是使用暴力破解,也就是Brute Force(BF或蛮力搜索) 算法,将匹配串和模式串左对齐,然后从左向右一个 ...

随机推荐

  1. mySQL (关系型数据库管理系统)

    MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RD ...

  2. Aaron Swartz Rewriting Reddit中关于web.py的创建思路

    这天才少年居然自杀了,哎 原文点这 So how should things work? The first principle is that code should be clear and si ...

  3. uva11542

    https://vjudge.net/problem/UVA-11542 xor高斯消元... 答案为2^f-1 其实书上有一个问题 样例有3种情况,其中4,6,15是绑在一起的,也就是他们必须满足一 ...

  4. 什么是需求Bug、设计Bug、功能bug?

    首先什么是需求Bug.设计Bug.功能bug? 需求Bug,指由于客户需求描述不清晰或错误.需求收集人员自身原因及需求本身模糊难于分析.获取等原因,导致客户需求获取不准确,后期产品不能满足客户.用户的 ...

  5. openssh常用命令记录

    command description date ssh [user@]hostname[:port] 登录远程机器 2017-03-21 scp <local_file> <use ...

  6. CodeForces 446A DZY Loves Sequences (DP+暴力)

    题意:给定一个序列,让你找出一个最长的序列,使得最多改其中的一个数,使其变成严格上升序列. 析:f[i] 表示以 i 结尾的最长上升长度,g[i] 表示以 i 为开始的最长上升长度,这两个很容易就求得 ...

  7. STL---vector的内存分配策略

    2级策略,过程如下: 第一级 __malloc_alloc_template内存分配器 该分配器是对malloc.realloc以及free的封装: 第二级  __default_alloc_temp ...

  8. log4j2异步日志解读(一)AsyncAppender

    log4j.logback.log4j2 历史和关系,我们就在这里不展开讲了.直接上干货,log4j2突出于其他日志的优势,异步日志实现. 看一个东西,首先看官网文档 ,因为前面文章已经讲解了disr ...

  9. win7升级到win10不能上网解决方法

    不要相信360的网络诊断了,都是坑货,没有什么用.下面的方法亲测有效.如君不行,那估计是win10版本不一样,原因另寻. 1.以管理员身份运行CMD,输入netsh winsock reset. 2. ...

  10. Python,报错NameError: name 'math' is not defined

    1 #-*- coding : utf-8 -*- 2 import math 3 4 def move(x, y, step, angle=0): 5 nx = x + step * math.co ...