<更新提示>

<第一次更新>


<正文>

字符串模式匹配

我们要先了解一下问题是什么。

模式匹配是数据结构中字符串的一种基本运算,给定一个子串,要求在某个字符串中找出与该子串相同的所有子串,这就是模式匹配。

KMP

然后我们来认识一下今天的主角\(KMP\)。

\(KMP\)算法是一种用来解决字符串模式匹配问题的一个经典算法,其能够在线性时间内求出在一个字符串中是否出现了另一个指定字符串,以及出现的位置,出现的次数。

形式化一下问题:给定一个字符串\(A\)和一个字符串\(B\),求\(B\)在\(A\)中的出现次数。

最长前后缀匹配

约定:我们将\(A\)称为主串,\(B\)为匹配串,两个字符串均从下标\(1\)开始储存,对于形如\(substr(l,r)\)认为是字符串中连续一部分。

对于字符串\(B\),\(KMP\)算法中有一个非常重要的关键数组,我们将其称为\(next\)数组,对于\(next_i\),其定义为:字符串\(B\)的\(substr(1,i)\)中,前缀和后缀和最大匹配长度,即\(\max\{next_i\}\),使得$$substr(1,next_i)=substr(i-next_i+1,i)$$

举个例子吧:\(B=ababab\),则\(next_6=4\),因为\(substr(1,4)=substr(3,6)=abab\)。

解决模式匹配问题

假设我们能够在线性时间内求出\(next\)数组,我们可以用如下方式求解该问题。

设\(f_i\)代表主串\(i\)位置的最长匹配长度,枚举\(i\)分别作为主串的指针,并声明一个变量\(j\)作为匹配串的指针,对于\(i\)移动到一个新的位置,我们尝试将\(j\)也向后移动一位,如果匹配,则更新一下当前位置的最优答案\(f_i\)即可。

那么对于不匹配的情况,我们可以用如下方法处理:虽然\(a_i\)与\(b_{j+1}\)不匹配,但我们知道主串的\(substr(i-j,i-1)\)与匹配串的\(substr(1,j)\)是相互匹配的,我们尝试用\(next\)数组来移动指针\(j\)。已知,匹配串中\(substr(j-next_j+1,j)=substr(1,next_j)\),由于匹配串中\(substr(j-next_j+1,j)\)必然也是和主串的一部分匹配的,我们可以直接利用\(next\)数组,使\(j=next_j\),让\(substr(1,next_j)\)移到原来\(substr(j-next_j+1,j)\)的位置,和主串重新进行匹配,继续求解问题。

匹配完成后,更新\(f_i=j\)即可。

\(Code:\)

inline void mate(void)
{
for(int i=1,j=0;i<=n;i++)
{
while(j&&(j==n||a[i]!=b[j+1]))
j=next[j];
if(a[i]==b[j+1])j++;
f[i]=j;
if(f[i]==m)ans++;
}
}

关于正确性,这样必然是正确的,不然将与\(next\)的极大性矛盾。

求解next数组

考虑求解\(next\)数组。如果直接暴力的话,时间复杂度将比求解主问题的时间复杂度还高,我们可以这样考虑,对于原问题,我们求解的是主串和匹配串的最长匹配,而对于\(next\)数组,我们求解的是匹配串的前后缀最长匹配,本质上,这两个问题的一样的,我们可用相同的方法来求解:用匹配串本身 匹配 匹配串,代码几乎是相同的。

\(Code:\)

inline void selfmate(void)
{
next[1]=0;
for(int i=2,j=0;i<=m;i++)
{
while(j&&b[i]!=b[j+1])
j=next[j];
if(b[i]==b[j+1])j++;
next[i]=j;
}
}

模板

\(Code:\)

#include<bits/stdc++.h>
using namespace std;
const int LENTH=1e6+20;
char a[LENTH],b[LENTH];
int next[LENTH],f[LENTH],n,m,ans;
inline void input(void)
{
scanf("%s",a+1);
n=strlen(a+1);
scanf("%s",b+1);
m=strlen(b+1);
}
inline void selfmate(void)
{
next[1]=0;
for(int i=2,j=0;i<=m;i++)
{
while(j&&b[i]!=b[j+1])
j=next[j];
if(b[i]==b[j+1])j++;
next[i]=j;
}
}
inline void mate(void)
{
for(int i=1,j=0;i<=n;i++)
{
while(j&&(j==n||a[i]!=b[j+1]))
j=next[j];
if(a[i]==b[j+1])j++;
f[i]=j;
if(f[i]==m)ans++;
}
}
int main(void)
{
input();
selfmate();
mate();
printf("%d\n",ans);
return 0;
}

接下来会有一道例题。

Censoring(USACO)

Description

Farmer John has purchased a subscription to Good Hooveskeeping magazine for his cows, so they have plenty of material to read while waiting around in the barn during milking sessions. Unfortunately, the latest issue contains a rather inappropriate article on how to cook the perfect steak, which FJ would rather his cows not see (clearly, the magazine is in need of better editorial oversight).

FJ has taken all of the text from the magazine to create the string S of length at most 10^6 characters. From this, he would like to remove occurrences of a substring T to censor the inappropriate content. To do this, Farmer John finds the first occurrence of T in S and deletes it. He then repeats the process again, deleting the first occurrence of T again, continuing until there are no more occurrences of T in S. Note that the deletion of one occurrence might create a new occurrence of T that didn't exist before.

Please help FJ determine the final contents of S after censoring is complete

有一个S串和一个T串,长度均小于1,000,000,设当前串为U串,然后从前往后枚举S串一个字符一个字符往U串里添加,若U串后缀为T,则去掉这个后缀继续流程。

Input Format

The first line will contain S. The second line will contain T. The length of T will be at most that of S, and all characters of S and T will be lower-case alphabet characters (in the range a..z).

Output Format

The string S after all deletions are complete. It is guaranteed that S will not become empty during the deletion process.

Sample Input

whatthemomooofun
moo

Sample Output

whatthefun

解析

题意:就是让你不断地删除匹配串,每一次删除,将主串删除部分的两边合并构成新的主串,最后输出主串。

那么我们就用\(KMP\)算法就可以了,对于删除操作,我们可以直接用栈来模拟,栈中记录主串还存在的字符的下标,对于得到了一个完整的匹配,将栈顶被匹配掉的若干个下标弹出即可。

\(Code:\)

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+20;
char a[N],b[N];
int n,m,top,next[N],f[N],s[N];
inline void input(void)
{
scanf("%s",a+1);
scanf("%s",b+1);
n=strlen(a+1);
m=strlen(b+1);
}
inline void selfmate(void)
{
next[1]=0;
for(int i=2,j=0;i<=m;i++)
{
while(j&&b[i]!=b[j+1])
j=next[j];
if(b[i]==b[j+1])j++;
next[i]=j;
}
}
inline void mate(void)
{
for(int i=1,j=0;i<=n;i++)
{
while(j&&(j==m||a[i]!=b[j+1]))
j=next[j];
if(a[i]==b[j+1])j++;
f[i]=j;
s[++top]=i;
if(f[i]==m)
{
top-=m;
j=f[s[top]];
}
}
}
int main(void)
{
input();
selfmate();
mate();
for(int i=1;i<=top;i++)
printf("%c",a[s[i]]);
return 0;
}

<后记>

『字符串模式匹配 KMP』的更多相关文章

  1. 字符串模式匹配KMP算法

    一篇不错的博客:http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html KMP字符串模式匹配通俗点说就是一种在一个字符串中 ...

  2. 字符串模式匹配——KMP算法

    KMP算法匹配字符串 朴素匹配算法   字符串的模式匹配的方法刚开始是朴素匹配算法,也就是经常说的暴力匹配,说白了就是用子串去和父串一个一个匹配,从父串的第一个字符开始匹配,如果匹配到某一个失配了,就 ...

  3. 数据结构4.3_字符串模式匹配——KMP算法详解

    next数组表示字符串前后缀匹配的最大长度.是KMP算法的精髓所在.可以起到决定模式字符串右移多少长度以达到跳跃式匹配的高效模式. 以下是对next数组的解释: 如何求next数组: 相关链接:按顺序 ...

  4. KMP字符串模式匹配详解(转)

    来自CSDN     A_B_C_ABC 网友 KMP字符串模式匹配通俗点说就是一种在一个字符串中定位另一个串的高效算法.简单匹配算法的时间复杂度为O(m*n);KMP匹配算法.可以证明它的时间复杂度 ...

  5. 『Python基础-4』字符串

    # 『Python基础-4』字符串 目录 1.什么是字符串 2.修改字符串 2.1 修改字符串大小 2.2 合并(拼接)字符串 2.3 使用乘号'*'来实现字符串的叠加效果. 2.4 在字符串中添加空 ...

  6. KMP字符串模式匹配详解(zz)

    刚看到位兄弟也贴了份KMP算法说明,但本人觉得说的不是很详细,当初我在看这个算法的时候也看的头晕昏昏的,我贴的这份也是网上找的.且听详细分解: KMP字符串模式匹配详解 来自CSDN     A_B_ ...

  7. KMP字符串模式匹配详解

    KMP字符串模式匹配详解 http://www.cppblog.com/oosky/archive/2006/07/06/9486.html

  8. 2017-2018-2 20155303『网络对抗技术』Exp9:Web安全基础

    2017-2018-2 『网络对抗技术』Exp9:Web安全基础 --------CONTENTS-------- 一.基础问题回答 1.SQL注入攻击原理,如何防御? 2.XSS攻击的原理,如何防御 ...

  9. 字符串模式匹配sunday算法

    文字部分转自:http://www.cnblogs.com/mr-ghostaqi/p/4285868.html 代码是我自己写的 今天在做LeetCode的时候,碰到一个写字符串匹配的题目: htt ...

随机推荐

  1. vue 事件修饰符

    1.用.stop来阻止冒泡(点击click按钮之后,先执行clickBtn2方法,然后执行clickBtn1方法,.stop命令阻止了clickBtn1方法的执行) 2.使用.prevent命令来阻止 ...

  2. 一、OpenStack环境准备及共享组件安装

    一.OpenStack部署环境准备: 1.关闭防火墙所有虚拟机都要操作 # setenforce 0 # systemctl stop firewalld 2.域名解析所有虚拟机都要操作 # cat ...

  3. VS2015|Visual Studio Enterprise 2015简体中文版(企业版)

    Microsoft Visual Studio(简称VS)是美国微软公司的开发工具包系列产品.Visual Studio 2015 是一个丰富的集成开发环境,可用于创建出色的 Windows.Andr ...

  4. 爬虫之图片懒加载技术及js加密

    图片懒加载 图片懒加载概念: 图片懒加载是一种网页优化技术.图片作为一种网络资源,在被请求时也与普通静态资源一样,将占用网络资源,而一次性将整个页面的所有图片加载完,将大大增加页面的首屏加载时间.为了 ...

  5. less是什么?直接用css好还是less好

    问:Less是一个动态CSS语言框架,Less扩展了CSS的动态特性 [1]:从实现角度来说,直接用css看起来能方便一些,而less还要编译? [2]:技术上好像灵活,但是从使用者的角度来说,css ...

  6. Largest Rectangle in a Histogram [POJ2559] [单调栈]

    题意一个围挡由n个宽度为1的长方形挡板下端对齐后得到,每个长方形挡板的高度为hi.我们把其抽象成一个图形,问这个图形中包含的面积最大的长方形是多大? 输入多行数据,每行第一个为n,后面n个数,代表hi ...

  7. socket error:10053

    系统提示:10053,由于超时或其它失败,连接中止 服务端和客户端并没有出现连接错误或主动关闭连接 发生这个错误的原因往往是连接上了,但是长时间没有通信,所以连接被挂起了 防止的办法就是自己设计心跳包 ...

  8. 对象转JSON

    /// <summary> /// 把对象序列化 JSON 字符串 /// </summary> /// <typeparam name="T"> ...

  9. 机器学习--------SVM

    #SVM的使用 (结合具体代码说明,代码参考邹博老师的代码) 1.使用numpy中的loadtxt读入数据文件 data:鸢尾花数据 5.1,3.5,1.4,0.2,Iris-setosa 4.9,3 ...

  10. [bzoj1059]矩阵游戏

    虽然是一道水难题,但是我这种蒟蒻还是要讲一讲的. Description 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏——矩阵游戏.矩阵游戏在一个N *N黑白方阵进行(如同国际 ...