字符串匹配(一)——从暴力匹配到KMP算法
2018-03-24 15:40
393 查看
现在有两个字符串:s1和s2,现在要你输出s2在s1当中每一次出现的位置,你会怎么做?
一、暴力匹配算法
1.1 基本思路
用两个指针分别指向当前匹配到的位置,并对当前状态进行分类讨论:若相同则继续往下匹配,否则回溯
1.2 大致思路
用i来存储s1当前匹配到的位置,用j来存储s2当前匹配到的位置,则可得初始状态下i=j=0
对于当前状态,有两种可能性:
①:s1[i]==s2[j]。则i++,j++
②:s1[i]!=s2[j]。则i-=(j-1),j=0
1.3 评价
时间复杂度:O(n^m)。显然,这个方法效率并不高,每一次回溯要耗去大量时间,能不能进行优化呢?
二、KMP算法
1.1 简介
KMP算法是对暴力匹配算法的改进,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为Knuth-Morris-Pratt算法(简称KMP算法)。
1.2 基本思路
KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个Next[]函数,函数本身包含了模式串的局部匹配信息。
1.3 大致思路
还是用i来存储s1当前匹配到的位置,用j来存储s2当前匹配到的位置,则可得初始状态下i=j=0
对于当前状态,有两种可能性:
①:s1[i]==s2[j]。则i++,j++
②:s1[i]!=s2[j]。则j=Next[j](i不变)
其中Next[]数组存储的是当前这一位的部分匹配值(这在后面会详细介绍),所以只要让j变成Next[j],就可以继续对当前字符串进行匹配了,省去了i回溯所耗去的大量时间
1.4 Next[]数组
在匹配过程中,你可以发现一个基本事实是:当s1[i]与s2[j]不匹配时,你其实知道前面j-1字符是什么。KMP算法的想法是,设法利用这个已知信息,不要把"搜索位置"移回已经比较过的位置,继续把它向后移,这样就提高了效率。
所以,我们就可以把当前所得到的部分匹配值给求出来。又由于对于同一个字符串,部分匹配值是固定不变的,所以可以把它存在Next[]数组里。
那么Next[]数组怎么求呢?有一个大佬说过,求Next[]数组的过程就是一个KMP的过程。
首先,令i=0,j=-1,Next[0]=-1,且当前要求的是Next[i+1]。则对于当前状态,有两种可能性:
①j==-1或s2[i]==s2[j]。则i++,j++,Next[i]=j
②j!=-1且s2[i]!=s2[j]。则j=Next[j]//把j赋值为j的部分匹配值
这样就可以轻松求出Next[]数组了
1.5 代码
注:如果您通过此文学会了KMP算法,请您点个赞再离开。当然,也欢迎在讨论区指出此文的不足处,作者会及时对此文加以修正
版权声明:转载请注明地址
一、暴力匹配算法
1.1 基本思路
用两个指针分别指向当前匹配到的位置,并对当前状态进行分类讨论:若相同则继续往下匹配,否则回溯
1.2 大致思路
用i来存储s1当前匹配到的位置,用j来存储s2当前匹配到的位置,则可得初始状态下i=j=0
对于当前状态,有两种可能性:
①:s1[i]==s2[j]。则i++,j++
②:s1[i]!=s2[j]。则i-=(j-1),j=0
1.3 评价
时间复杂度:O(n^m)。显然,这个方法效率并不高,每一次回溯要耗去大量时间,能不能进行优化呢?
二、KMP算法
1.1 简介
KMP算法是对暴力匹配算法的改进,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为Knuth-Morris-Pratt算法(简称KMP算法)。
1.2 基本思路
KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个Next[]函数,函数本身包含了模式串的局部匹配信息。
1.3 大致思路
还是用i来存储s1当前匹配到的位置,用j来存储s2当前匹配到的位置,则可得初始状态下i=j=0
对于当前状态,有两种可能性:
①:s1[i]==s2[j]。则i++,j++
②:s1[i]!=s2[j]。则j=Next[j](i不变)
其中Next[]数组存储的是当前这一位的部分匹配值(这在后面会详细介绍),所以只要让j变成Next[j],就可以继续对当前字符串进行匹配了,省去了i回溯所耗去的大量时间
1.4 Next[]数组
在匹配过程中,你可以发现一个基本事实是:当s1[i]与s2[j]不匹配时,你其实知道前面j-1字符是什么。KMP算法的想法是,设法利用这个已知信息,不要把"搜索位置"移回已经比较过的位置,继续把它向后移,这样就提高了效率。
所以,我们就可以把当前所得到的部分匹配值给求出来。又由于对于同一个字符串,部分匹配值是固定不变的,所以可以把它存在Next[]数组里。
那么Next[]数组怎么求呢?有一个大佬说过,求Next[]数组的过程就是一个KMP的过程。
首先,令i=0,j=-1,Next[0]=-1,且当前要求的是Next[i+1]。则对于当前状态,有两种可能性:
①j==-1或s2[i]==s2[j]。则i++,j++,Next[i]=j
②j!=-1且s2[i]!=s2[j]。则j=Next[j]//把j赋值为j的部分匹配值
这样就可以轻松求出Next[]数组了
1.5 代码
#include<bits/stdc++.h> #define N 2000 using namespace std; int Next[N+5];//存储部分匹配值 char s1[N+5],s2[N+5]; void GetNext()//求出Next[]数组 { int i=0,j=-1; Next[0]=-1; while(i<strlen(s2))//类似于一个KMP过程 { if(j==-1||s2[i]==s2[j]) i++,j++,Next[i]=j; else j=Next[j]; } } int main() { gets(s1),gets(s2); GetNext(); int i=0,j=0; while(i<=strlen(s1))//KMP过程 { if(j==-1||s1[i]==s2[j]) {i++,j++;if(j==strlen(s2)) printf("%d\n",i-strlen(s2)+1),j=Next[j];/*找到一个解,进行输出*/} else j=Next[j];//对j进行回溯,不改变i值 } return 0; }
注:如果您通过此文学会了KMP算法,请您点个赞再离开。当然,也欢迎在讨论区指出此文的不足处,作者会及时对此文加以修正
版权声明:转载请注明地址
相关文章推荐
- 字符串匹配的KMP算法(部分匹配表:前缀---后缀)
- 字符串匹配(暴力匹配)
- 字符串匹配暴力匹配法和KMP匹配算法对比
- 字符串匹配的算法(暴力算法和KMP算法)
- 字符串匹配算法(暴力匹配和KMP)
- 3. 字符串匹配算法:朴素的匹配算法、KMP算法。
- 字符串匹配(java)实现,普通的匹配和KMP算法 (参考)
- 字符串匹配暴力算法 与 字符串匹配的KMP算法
- 字符串匹配---暴力匹配算法
- 字符串匹配-KMP算法
- 寒假集训-字符串匹配的KMP算法
- 字符匹配 kmp算法
- [算法系列之十二]字符串匹配之蛮力匹配
- HDU-3746 Cyclic Nacklace 字符串匹配 KMP算法 求最小循环节
- 字符串匹配KMP算法中Next[]数组求法
- 字符串匹配之KMP算法
- 字符串匹配-KMP算法学习笔记
- 字符串匹配KMP算法
- 字符串匹配--KMP算法
- 字符串匹配的KMP算法