前言

此篇笔记根据自己的理解和练习心得来解释算法,只代表个人观点,如有不足请指出(我刚学QWQ)

浅谈字符串匹配

设想一个场景,假设你是一个净化网络语言环境的管理员,每天需要翻阅大量的文章和帖子来查找敏感字,那么这个时候很简单的可以想到可以运用字符串匹配来做到,但是朴素的单模式字符串匹配耗用时间多,那么在这里我们就可以运用高效率的\(KMP\)算法来解决。

算法对比

  • 朴素单模式字符串匹配算法

朴素的单模式串匹配大概就是枚举每一个文本串元素,然后从这一位开始不断向后比较,每次比较失败之后都要从头开始重新比对

给定一个文本串(要查找符合条件的字符串),以及一个模式串(需要匹配的字符串)

模式串:abcab
文本串:abcacababcab

一般的思想就是,当我们在第五位失配时,我们会从当前模式串的第一位所处在文本串的位置的后一位开始与模式串的第一位进行匹配,直到匹配成功位置,就会出现以下的情况

模式串:   abcab
文本串:abcacababcab

这一种算法的正确性是100%的,但是复杂度显然不是那么喜人,一般来说,期望时间复杂度可以为\(O(n+m)\)的,但是一些有心的出题人甚至可以卡到\(O(nm)\),所以这个算法仅仅用于暴力打法即可。

  • \(KMP\)字符匹配算法

对于失配以后的字符串,不需要去从头开始枚举浪费时间,而是根据预先处理好的值来进行枚举即可,也就是寻找最优历史处理,

根据处理的过程,时间复杂度为\(O(n+m)\)

依旧是给定一个样例来说明

模式串:abcabc
文本串:abcabdababcabc

在这个样例中我们可以看到,在第六位的时候失配了,这个时候有一个\(KMP\)算法的专门小\(trick\),我们观察字符串可以发现的是,在模式串中,失配的前一位第五位在这整个模式串中可以找到一个和他相匹配的字符,也就是第二位的\(b\),那么我们现在就可以把模式串的匹配长度跳转到\(2\)继续查找,那么为什么可以这样做呢,因为我们可以发现,在匹配的时候,第五位的\(b\)之所以可以转移到第二位,靠的就是以第五位结尾的一个子串,可以与从\(1-2\)这个范围内的子串一一对应起来,也就是完全的按位匹配。

那么转移过来就是这样的

模式串:   abcabc
文本串:abcabdababcabc

通过这个方法我们可以节省一大堆无用的时间。

思路分析

首先设置\(kmp\)数组为失配数组,也就是存储当匹配失败后跳转到接下来模式串匹配的最优的位置,因为相比较于文本串,模式串更加的灵活多变,处理起来也很方便,那么处理失配数组的时候将模式串当做处理串。

那么核心就在于如何来处理失配数组的值

我们要明确的是,在上面条件的基础上,我们要考虑的是当模式串的第\(i\)为失配以后,如何来调到最优的位置继续进行匹配,因为在文本串当中\(i\)以前的位置都已经失效了,那么我们对于每一个\(kmp_i\)要记录的是:

在模式串\(str\)中,我们可以找到一个最优的位置\(j\),满足\(i\geq j\)并且满足\(str_i=str_j\),并且在\(j!=1\)的时候,有从\(str_1-str_{j-1}\)分别与\(str_{i-j+1}-str_{j-1}\)按位匹配。

简单来说就是在模式串中,存在一个长度为\(len\)的以\(1\)开头以\(j\)结尾的子串与以\(i-j+1\)开头以\(i\)结尾的子串完全相同

代码实现

#include<iostream>
#include<cstring>
#include<stack>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<queue>
#include<map>
using namespace std;
const int N=1e6+9;
int kmp[N],j;
int lena,lenb;
char a[N],b[N];
int main()
{
cin>>a+1;
cin>>b+1;
lena=strlen(a+1);
lenb=strlen(b+1);
//预处理kmp数组
for(int i=2;i<=lenb;i++)//第一个字符一定是匹配的所以不需要i=1
{
while(b[i]!=b[j+1]&&j)//如果不匹配就往回跳
j=kmp[j];
if(b[i]==b[j+1])j++;//遇见相同的就向右移动
kmp[i]=j;
}
j=0;
for(int i=1;i<=lena;i++)
{
while(j&&b[j+1]!=a[i])
j=kmp[j];//通过自己匹配自己来求得每一个点的kmp值
if(b[j+1]==a[i])
j++;
if(j==lenb)
{
printf("%d\n",i-lenb+1);//这个是开始的值
j=kmp[j];
}
}
for(int i=1;i<=lenb;i++)
printf("%d ",kmp[i]);
return 0;
}

KMP算法 字符串匹配(看猫片)的更多相关文章

  1. KMP算法——字符串匹配

    正直找工作面试巅峰时期,有幸在学校可以听到July的讲座,在时长将近三个小时的演讲中,发现对于找工作来说,算法数据结构可以算是程序员道路的一个考量吧,毕竟中国学计算机的人太多了,只能使用这些方法来淘汰 ...

  2. KMP算法---字符串匹配

    算法细节详见点击打开链接和点击打开链接 #include <stdio.h> #include <stdlib.h> #define N 7 #define M 15 void ...

  3. 字符串匹配的KMP算法-16张图片看明白

    作者: 阮一峰 日期: 2013年5月 1日 字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另 ...

  4. KMP算法——字符匹配

     暴力匹配: 假设现在我们面临这样一个问题:有一个文本串S,和一个模式串P,现在要查找P在S中的位置,怎么查找呢? 如果用暴力匹配的思路,并假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置, ...

  5. 算法——字符串匹配之BM算法

    前言 Boyer-Moore算法是一种基于后缀匹配的模式串匹配算法(简称BM算法),后缀匹配就是模式串从右到左開始比較,但模式串的移动依旧是从左到右的.在实践中.BM算法效率高于前面介绍的<KM ...

  6. HDU 1711(KMP)字符串匹配

    链接  HDU 1711 Number Sequence KMP 算法 我以自己理解写的,写的不对,不明白的地方海王子出来,一起共同学习: 字符串匹配 就是KMP,一般思想,用一个for循环找开头   ...

  7. KMP算法-字符匹配

    字符匹配模式-KMP算法 j直接跳到了2的位置,因为在之前的都相同. 那么就需要求如果不等了之后,j需要回跳的位置next[j] 如果tk'与tj相等,则next [j+1]=k'+1 如果tk'与t ...

  8. KMP快速字符串匹配

    KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现.KMP算法的关键是利用匹配失败后的信息,从错误中吸取经验,尽量减少模式串与主串的匹配次数以 ...

  9. 算法——字符串匹配Rabin-Karp算法

    前言 Rabin-Karp字符串匹配算法和前面介绍的<朴素字符串匹配算法>类似,也是相应每一个字符进行比較.不同的是Rabin-Karp採用了把字符进行预处理,也就是对每一个字符进行相应进 ...

随机推荐

  1. 徐汉彬:Web系统大规模并发——电商秒杀与抢购

    摘要:电商的秒杀和抢购,从技术的角度来说,会对Web系统产生巨大的考验.本期<问底>,徐汉彬将带大家关注秒杀和抢购的技术实现和优化,同时,从技术层面揭开,为什么我们总是不容易抢到火车票的原 ...

  2. Spring事务管理?

    事务管理方式: 1.编码方案,不建议使用,具有侵入性,在原有的业务代码基础上去添加事物管理代码 2.声明式事务控制,基于AOP对目标进行代理,不具有侵入性,不需要修改原来的业务代码

  3. 如何在Nginx不绑定域名下使用SSL/TLS证书?

    前提 该文主要记录如何在没有购买域名的情况下使用SSL/TLS协议,即地址前面的http变成了https.但是这样的SSL协议是会被浏览器认为是不安全的.在开发或者测试环境可以这样搞,生产环境下还是乖 ...

  4. 数据库索引的基石----B树

    数据结构相对来说比较枯燥, 我尽量用最易懂的话,来把B树讲清楚.学过数据结构的人都接触过一个概念二叉树,简单来说,就是每个父节点最多有两个子节点.为了在二叉树上更快的进行元素的查找,人们通过不断的改进 ...

  5. 1001 害死人不偿命的(3n+1)猜想 (15分)

    卡拉兹(Callatz)猜想: 对任何一个正整数 n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把 (3n+1) 砍掉一半.这样一直反复砍下去,最后一定在某一步得到 n=1.卡拉兹在 1950 ...

  6. Head First 设计模式 —— 00. 引子

    Head First 学习原则 P xxx 可视化:图片使得学习效率更高,更易懂 交谈式:第一人称交谈方式讲述学习内容更易引起注意 多思考:自主思考练习题和拓展知识的问题 保持注意力集中:将知识融合进 ...

  7. node.js中使用http-proxy-middleware请求转发给其它服务器

    var express = require('express');var proxy = require('http-proxy-middleware'); var app = express(); ...

  8. 网络之HTTPS

    文章目录 HTTPS的基本概念 HTTP和HTTPS的区别 HTTPS的优点 对称加密和非对称加密 对称加密 非对称加密 HTTPS采用的加密方式 认证 证书的组成 使用openssl怎么制造证书 H ...

  9. Count PAT's (25) PAT甲级真题

    题目分析: 由于本题字符串长度有10^5所以直接暴力是不可取的,猜测最后的算法应该是先预处理一下再走一层循环就能得到答案,所以本题的关键就在于这个预处理的过程,由于本题字符串匹配的内容的固定的PAT, ...

  10. 【.NET 与树莓派】使用 GPIO 库

    上回老周在说准备工作的时候,提到过树莓派用金属盒散热的事情.有朋友会说,加了金属盒子接线不方便,就算用了"T"形板,毕竟是把导线延长了的.其实扩展板就是把原有的引脚引出(类似于延长 ...