算法 kmp算法
kmp算法是改进后的字符匹配算法,它与bf算法的区别是,每次从串与主串匹配失败后,从串与主串匹配的位置不同。
下面具体说下这两种算法的区别:
主串:BABCDABABCDABCED
从串:ABCDABCED
BF算法:
第一步:
B | A | B | C | D | A | B | A | B | C | D | A | B | C | E | D |
A |
从主串的第一个字符位置开始与从串第一个字符位置进行匹配,匹配失败
第二步:
B | A | B | C | D | A | B | A | B | C | D | A | B | C | E | D |
A | B | C | D | A | B | C |
从主串的第二个字符位置开始与从串第一个字符位置进行匹配,匹配失败
第三步:
B | A | B | C | D | A | B | A | B | C | D | A | B | C | E | D |
A |
从主串的第三个字符位置开始与从串第一个字符位置进行匹配,匹配失败
...........
第七步:
B | A | B | C | D | A | B | A | B | C | D | A | B | C | E | D |
A |
从主串的第七个字符位置开始于从串第一个字符位置进行匹配,匹配失败
第八步:
B | A | B | C | D | A | B | A | B | C | D | A | B | C | E | D |
A | B | C | D | A | B | C | E | D |
匹配成功,这个就是BF算法,每次匹配失败后要从主串的下一个字符位置与从串的第一个字符接着进行匹配。
kmp算法:
第一步:
B | A | B | C | D | A | B | A | B | C | D | A | B | C | E | D |
A |
主串与从串的第一个字符不匹配
第二步:
B | A | B | C | D | A | B | A | B | C | D | A | B | C | E | D |
A | B | C | D | A | B | C |
第三步:
B | A | B | C | D | A | B | A | B | C | D | A | B | C | E | D |
A | B | C |
这里就和bf不一样了,其原因就是从串中字符有相同的一部分(AB),这里先知道区别,待会我会说它的实现过程
第四步:
B | A | B | C | D | A | B | A | B | C | D | A | B | C | E | D |
A | B | C | D | A | B | C | E | D |
如果看不懂的话,下面会讲清楚,然后根据程序找下标就可以知道原因了。
kmp算法分两部分:①next数组(kmp算法的核心)
②字符串的匹配
在讲解next数组时,顺便把前缀和后缀的知识也说了。
比如上面的从串:ABCDABCED(前缀是从第一个字符数,但后缀不是倒着数,它也是顺着数,看下面的写法吧)
第一个字符前,它没有串,所以没有前缀和后缀,则它也没有最长长度,我把它的长度初始化为0。
第二个字符前,它的串是A,前缀和后缀是不能包含串本身,所以它没有前缀和后缀,长度为0。
第三个字符前,它的串是AB,前缀是A,后缀是B,不匹配,长度为0。
第四个字符前,它的串是ABC,第一种,前缀是A,后缀是C,不匹配,长度为0,
第二种,前缀是AB,后缀是BC,不匹配,长度为0,
所以最长长度为0。
第五个字符前,它的串是ABCD,第一种,前缀是A,后缀是D,不匹配,长度为0,
第二种,前缀是AB,后缀是CD,不匹配,长度为0,
第三种,前缀是ABC,后缀是BCD,不匹配,长度为0,
所以最长长度为0。
第六个字符前,它的串是ABCDA,第一种,前缀是A,后缀是A,匹配,长度为1,
第二种,前缀是AB,后缀是DA,不匹配,长度为0,
第三种,前缀是ABC,后缀是CDA,不匹配,长度为0,
第四种,前缀是ABCD,后缀是BCDA,不匹配,长度为0,
所以最长长度为1。
第七个字符前,它的串是ABCDAB,第一种,前缀是A,后缀是B,不匹配,长度为0,
第二种,前缀是AB,后缀是AB,匹配,长度为2,
第三种,前缀是ABC,后缀是DAB,不匹配,长度为0,
第四种,前缀是ABCD,后缀是CDAB,不匹配,长度为0,
第五种,前缀是ABCDA,后缀是BCDAB, 不匹配,长度为0,
所以最长长度为2。
第八个字符前,它的串是ABCDABC,第一种,前缀是A,后缀是C,不匹配,长度为0,
第二种,前缀是AB,后缀是BC,不匹配,长度为0,
第三种,前缀是ABC,后缀是ABC,匹配,长度为3,
第四种,前缀是ABCD,后缀是DABC,不匹配,长度为0,
第五种,前缀是ABCDA,后缀是CDABC,不匹配,长度为0,
第六种,前缀是ABCDAB,后缀是BCDABC,不匹配,长度为0,
所以最长长度为3。
第九个字符前,它的串是ABCDABCE,第一种,前缀是A,后缀是E,不匹配,长度为0,
第二种,前缀是AB,后缀是CE,不匹配,长度为0,
第三种,前缀是ABC,后缀是BCE,不匹配,长度为0,
第四种,前缀是ABCD,后缀是ABCE,不匹配,长度为0,
第五种,前缀是ABCDA,后缀是DABCE,不匹配,长度为0,
第六种,前缀是ABCDAB,后缀是CDABCE,不匹配,长度为0,
第七种,前缀是ABCDABC,后缀是BCDABCE,不匹配,长度为0,
所以最长长度为0。
然后根据我们求出来的最长长度,就能绘制出next表了,
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
从串 | A | B | C | D | A | B | C | E | D |
next | 0 | 0 | 0 | 0 | 0 | 1 | 2 | 3 | 0 |
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
从串 | A | B | C | D | A | B | C | E | D |
next | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 |
第二个B与第一个B的next值一样为0,第二个C与第一个C的next值一样为0。
这就是next数组及其改进后的next数组。
next数组程序:
void Get_next(int *next, string s2)
{
int i = 1;
int j = 0;
next[i] = 0;
while(i <= s2.length())
{
if(j == 0 || s2[i - 1] == s2[j - 1])
{
i++;
j++;
if(s2[i - 1] == s2[j - 1])
next[i] = next[j];
else
next[i] = j - 1;
}
else
j = next[j];
}
}
如果你理解了next数组的求值方法,根据bf算法的思路应该可以写出kmp字符匹配函数,
下面是kmp算法的总体程序:
#include <iostream>
#include <string>
using namespace std;
//求next数组下标
void Get_next(int *next, string s2)
{
int i = 1;
int j = 0;
next[i] = 0;
while(i <= s2.length())
{
if(j == 0 || s2[i - 1] == s2[j - 1])
{
i++;
j++;
if(s2[i - 1] == s2[j - 1])
next[i] = next[j];
else
next[i] = j - 1;
}
else
j = next[j];
}
// for(int k = 1; k < 10; k++)
// cout << next[k] << endl;
}
//匹配部分
int kmp(string s1, string s2, int pos)
{
int next[100];
Get_next(next, s2);
int i = 0;
int j = 0;
while(i < s1.length() && j < s2.length())
{
if(j == 0 || s1[i] == s2[j])
{
i++;
j++;
}
else
{
j = next[j + 1];
}
}
if(j >= s2.length())
return i - s2.length();
return -1;
}
int main()
{
string s1= "babcdababcdabced";
string s2 = "abcdabced";
int pos;
cin >> pos;
cout << kmp(s1, s2 ,pos) << endl;
return 0;
}
本程序只是个人的想法和思路,若有错误还请大家提出,若有不明白的地方,请在下面评论,谢谢大家啦!
对了,我的算法应该存在问题,希望多多指出。
算法 kmp算法的更多相关文章
- 数据结构与算法--KMP算法查找子字符串
数据结构与算法--KMP算法查找子字符串 部分内容和图片来自这三篇文章: 这篇文章.这篇文章.还有这篇他们写得非常棒.结合他们的解释和自己的理解,完成了本文. 上一节介绍了暴力法查找子字符串,同时也发 ...
- 经典算法 KMP算法详解
内容: 1.问题引入 2.暴力求解方法 3.优化方法 4.KMP算法 1.问题引入 原始问题: 对于一个字符串 str (长度为N)和另一个字符串 match (长度为M),如果 match 是 st ...
- 笔记-算法-KMP算法
笔记-算法-KMP算法 1. KMP算法 KMP算法是一种改进的字符串匹配算法,KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的.具体实现就是实现一 ...
- 值得花费一周研究的算法 -- KMP算法(indexOf)
KMP算法是由三个科学家(kmp分别是他们名字的首字母)创造出来的一种字符串匹配算法. 所解决的问题: 求文本字符串text内寻找第一次出现字符串s的下标,若未出现返回-1. 例如 text : &q ...
- [C++] [算法] KMP算法
KMP串匹配算法是一个经典的算法. 传统BF算法是传统的字符串匹配算法.很好理解.叶实现.但时间复杂度太高. 本文将从字符串模式字符串被称为.为了匹配字符串被称为主弦. KMP配时能够少移动从串的位置 ...
- 程序员必会算法-KMP算法
KMP算法是一种优秀的字符串匹配算法,字符串匹配的常规算法是一步一步进行移位和比较操作,直至找到完全相匹配的字符串. 下面通过一个例子,为大家仔细说明KMP算法的使用和思路: 问题: 在字符串“DEA ...
- BF算法 + KMP算法
准备: 字符串比大小:比的就是字符串里每个字符的ASCII码的大小.(其实这样的比较没有多大的意义,我们关心的是字符串是否相等,即匹配等) 字符串的存储结构:同线性表(顺序存储+链式存储) 顺序存储结 ...
- 图解算法——KMP算法
KMP算法 解决的是包,含问题. Str1中是否包含str2,如果包含,则返回子串开始位置.否则返回-1. 示例1: Str1:abcd123def Str2:123d 暴力法: 从str1的第一个字 ...
- 字符串匹配算法——KMP算法
处理字符串的过程中,难免会遇到字符匹配的问题.常用的字符匹配方法 1. 朴素模式匹配算法(Brute-Force算法) 求子串位置的定位函数Index( S, T, pos). 模式匹配:子串的定位操 ...
随机推荐
- BZOJ 3687: 简单题 bitset
3687: 简单题 Time Limit: 10 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description 小呆开始研究集合论了,他 ...
- 【JsonView工具】谷歌浏览器中安装JsonView扩展程序
接口测试过程中,有时候要查看接口返回的数据(比如Get接口),为了更方便的查看,发现这个插件挺好用的. 实际开发工作中经常用到json数据,那么就会有这样一个需求:在谷歌浏览器中访问URL地址返回的j ...
- mysql 多行(GROUP_CONCAT)和多列(CONCAT)的合并函数
1,多行合并:把查询的一行或者多行进行合并. SELECT GROUP_CONCAT(md.data1) FROM DATA md,contacts cc WHERE md.conskey=cc.id ...
- vue项目中icon图标的完美引入
第一步: 进入阿里矢量图标库并登录 地址:https://www.iconfont.cn 第二步: 选择项目需要的图标添加到库 第三步: 选完之后点击右上角的购物车,打开后点击添加到项目,没有就自己建 ...
- Json解析注解 ---@SerializedName
项目前后端交互采用的是JSON传输,因为前后端沟通不多,经常造成数据格式不统一:在不想后台改动太多下,需要使用@SerializedName解决这个问题 解析数据使用的是Gson解析的json数据 @ ...
- c语言实现:三子棋
问题描述:两个游戏者在3*3棋盘里轮流作标记,如果一个人在行,列或者两个对角线可以作三个标记,则为获胜. 我们首先得打印菜单供玩家选择(可以选择玩游戏或者退出游戏) void menu() { pri ...
- CI、CD相关概念
1.CI:持续集成(CONTINUOUS INTEGRATION) 基本概念 CI的全称是Continuous Integration,表示持续集成. 在CI环境中,开发人员将会频繁地向主干提交代码. ...
- 微信小程序中把页面生成图片
这个问题我上网搜了一下,答案有多种,但是真正能用的没有几何.很多答案都是雷同,有的网友也不负责任,直接拿来照抄,自己也不跑一遍看看.哎,不说了,说多了全是泪.希望我们的技术达人在分享的时候,能够真实的 ...
- jsfl 删除库指定内容
var bitMap=fl.getDocumentDOM().getTimeline().layers [layLen_num-1].frames[0].elements[0]; fl.trace(b ...
- dump命令详解
1.简介: dump命令用于备份文件系统. dump为备份工具程序,可将目录或整个文件系统备份至指定的设备,或备份成一个大文件. 2.语法: dump [-cnu][-0123456789][-b & ...