字符串匹配算法(KMP)
字符串匹配运用很广泛,举个简单例子,我们每天登QQ时输入账号和密码,大家有没有想过账号和密码是怎样匹配的呢?登录需要多长时间和匹配算法的效率有直接的关系。
首先理解一下前缀和后缀的概念:
给出一个问题:现在有一个文本串S=“BBC ABCDAB ABCDABCDABDE”和一个搜索串(模式串)p="ABCDABD",要查找p在s中的位置。我们常用的一种方法就是暴力求解,暴力求解的思想是:让模式串从文本串的第一个字符开始往后匹配,假设现在文本串匹配到
i 位置,模式串匹配到 j 位置:
如果当前字符匹配成功,则 i++, j++
如果当前字符匹配不成功,i 要回溯 , j 要归零 ;
首先,字符串"BBC ABCDAB ABCDABCDABDE"的第一个字符与搜索词"ABCDABD"的第一个字符,进行比较。因为B与A不匹配,所以搜索词后移一位。
因为B与A不匹配,搜索词再往后移。
就这样,直到字符串有一个字符,与搜索词的第一个字符相同为止。
接着比较字符串和搜索词的下一个字符,还是相同。
直到字符串有一个字符,与搜索词对应的字符不相同为止。
这时,最自然的反应是,将搜索词整个后移一位,再从头逐个比较。这样做虽然可行,但是效率很差,因为你要把"搜索位置"移到已经比较过的位置,重比一遍。
相应代码如下:
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char s[100] , p[100] ;
cin >> s >> p ;
int lens = strlen(s) , lenp = strlen(p);
int i , j , k ;
bool flag = false ;
for(i = 0 ; i < lens ; i++ ) {
for(j = 0 , k = i ; j < lenp && k < lens ; j++)
if(s[k] == p[j])
k++ ;
else
break ;
if(j == lenp) {
cout << i + 1 << endl ;
flag = true ;
break ;
}
}
if(flag == false)
cout << "匹配失败" << endl ;
return 0;
}
以上代码可以进行简化:
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char s[100] , p[100] ;
cin >> s >> p ;
int lens = strlen(s) , lenp = strlen(p);
int i = 0 , j = 0 , k = 0 ;
while(i < lens && j < lenp) {
if(s[i] == p[j]) {
i++ ;
j++ ;
}
else{
i = i - j + 1 ;
j = 0 ;
}
}
if(j == lenp)
cout << i - j + 1 << endl ;
else
cout << "匹配失败" << endl ;
return 0;
}
暴力求解有很多比较都是多余的,下面介绍一种比较快速的查找方法。
KMP算法:
Knuth-Morris-Pratt字符串查找算法,简称“KMP”算法,常用于在一个文本串中查找一个模式串出现的位置。
思想:利用模式串中在匹配过程中,不匹配字符前面那一段最长前缀后缀,尽可能减少多余的匹配。
一个基本事实是,当空格与D不匹配时,你其实知道前面六个字符是"ABCDAB"。KMP算法的想法是,设法利用这个已知信息,不要把"搜索位置"移回已经比较过的位置,继续把它向后移,这样就提高了效率。"ABCDAB"之中有两个"AB",搜索词移动的时候,第一个"AB"向后移动4位,就可以来到第二个"AB"的位置。
首先需要对模式串进行处理,这里需要定义一个next数组,某个字符失配时,该字符对应的next 值会告诉你下一步匹配中,模式串应该跳到哪个位置。
代码雏形如下,其中next数组还未知:
#include <string.h>
using namespace std;
int main()
{
char s[100] , p[100] ;
cin >> s >> p ;
int lens = strlen(s) , lenp = strlen(p);
int i = 0 , j = 0 , k = 0 ;
while(i < lens && j < lenp) {
if(s[i] == p[j] || j == -1) {
i++ ;
j++ ;
}
else{
j = next[j] ;
}
}
if(j == lenp)
cout << i - j + 1 << endl ;
else
cout << "匹配失败" << endl ;
return 0;
}
下面求解next数组:
next数组中存储的就是当前模式串已匹配过的字符组成的字符串最长前缀后缀的长度:
字符串匹配算法(KMP)的更多相关文章
- 字符串匹配算法 - KMP
前几日在微博上看到一则微博是说面试的时候让面试者写一个很简单的字符串匹配都写不出来,于是我就自己去试了一把.结果写出来的是一个最简单粗暴的算法.这里重新学习了一下几个经典的字符串匹配算法,写篇文章以巩 ...
- 字符串匹配算法——KMP算法学习
KMP算法是用来解决字符串的匹配问题的,即在字符串S中寻找字符串P.形式定义:假设存在长度为n的字符数组S[0...n-1],长度为m的字符数组P[0...m-1],是否存在i,使得SiSi+1... ...
- 4种字符串匹配算法:KMP(下)
回顾:4种字符串匹配算法:BS朴素 Rabin-karp(上) 4种字符串匹配算法:有限自动机(中) 1.图解 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R ...
- 字符串匹配算法KMP算法
数据结构中讲到关于字符串匹配算法时,提到朴素匹配算法,和KMP匹配算法. 朴素匹配算法就是简单的一个一个匹配字符,如果遇到不匹配字符那么就在源字符串中迭代下一个位置一个一个的匹配,这样计算起来会有很多 ...
- 字符串匹配算法--KMP字符串搜索(Knuth–Morris–Pratt string-searching)C语言实现与讲解
一.前言 在计算机科学中,Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个主文本字符串S内查找一个词W的出现位置.此算法通过运用对这个词在不匹配时本身就包含足够的信息 ...
- 字符串匹配算法——KMP算法
处理字符串的过程中,难免会遇到字符匹配的问题.常用的字符匹配方法 1. 朴素模式匹配算法(Brute-Force算法) 求子串位置的定位函数Index( S, T, pos). 模式匹配:子串的定位操 ...
- [Algorithm] 字符串匹配算法——KMP算法
1 字符串匹配 字符串匹配是计算机的基本任务之一. 字符串匹配是什么?举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串& ...
- 字符串匹配算法——KMP、BM、Sunday
KMP算法 KMP算法主要包括两个过程,一个是针对子串生成相应的“索引表”,用来保存部分匹配值,第二个步骤是子串匹配. 部分匹配值是指字符串的“前缀”和“后缀”的最长的共有元素的长度.以“ABCDAB ...
- KMP Algorithm 字符串匹配算法KMP小结
这篇小结主要是参考这篇帖子从头到尾彻底理解KMP,不得不佩服原作者,写的真是太详尽了,让博主产生了一种读学术论文的错觉.后来发现原作者是写书的,不由得更加敬佩了.博主不才,尝试着简化一些原帖子的内容, ...
- 字符串匹配算法-kmp算法
一原理: 部分转自:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html 字 ...
随机推荐
- hdu 4545 魔法串 2013金山西山居创意游戏程序挑战赛——初赛(1)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4545 这题太坑了,小明的串可以任意删掉某个字符 这句话不知道大家是怎么理解的,我觉得应该是能够删除其中 ...
- MYSQL alter procedure alter function 它们只可以更改过程的特性,不可以更改过程的逻辑。
例子: delimiter // create procedure proc_a(in numberA int) 这样create procedure 是正确的 begin select number ...
- QT显示如何减轻闪屏(双缓冲和NoErase)
很多同志在些QT 程序后会遇见闪屏的问题, 有时速度非常快,但毕竟影响了显示效果,如何做到减轻屏幕抖动或闪屏呢?我曾试过如下的办法:1.使用双缓冲. 比如我们在一个Widget里面绘多个图的话, 先创 ...
- MySQL Binlog的介绍
binlog基本定义:二进制日志,也成为二进制日志,记录对数据发生或潜在发生更改的SQL语句,并以二进制的形式保存在磁盘中: 作用:MySQL的作用类似于Oracle的归档日志,可以用来查看数据库的变 ...
- Spring 构造注入 传參数
1. 提供相应的构造方法 //构造器注入 public class Bean6 { private String name; private Integer age; // 服务于构造器 ...
- Node.js笔记4
4. 文件系统 fs fs模块是文件操作的封装,提供了同步跟异步操作2个版本 * fs.readFile(filename,[encoding],[callback(err,data)]) 是最简单的 ...
- (转)ios跳转到通用页面
在代码中调用如下代码: [[UIApplicationsharedApplication] openURL:[NSURLURLWithString:@"prefs:root=LOCATION ...
- POJ 1151Atlantis 扫描线+线段树求矩形面积并
题目链接 #include <iostream> #include <vector> #include <cstdio> #include <cstring& ...
- [LeetCode]题解(python):135-Candy
题目来源: https://leetcode.com/problems/candy/ 题意分析: 有N个孩子站成一条线.每个孩子有个排名.要求1.每个孩子至少一个糖果,2.相邻的孩子,那么较高排名的孩 ...
- win7 资源管理器的背景色修改
主要参考 http://blog.sina.com.cn/s/blog_49c182c20100w3nb.html win7 通过dll修改背景色首先找到这个文件C:\Windows\Resource ...