字符串匹配运用很广泛,举个简单例子,我们每天登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)的更多相关文章

  1. 字符串匹配算法 - KMP

    前几日在微博上看到一则微博是说面试的时候让面试者写一个很简单的字符串匹配都写不出来,于是我就自己去试了一把.结果写出来的是一个最简单粗暴的算法.这里重新学习了一下几个经典的字符串匹配算法,写篇文章以巩 ...

  2. 字符串匹配算法——KMP算法学习

    KMP算法是用来解决字符串的匹配问题的,即在字符串S中寻找字符串P.形式定义:假设存在长度为n的字符数组S[0...n-1],长度为m的字符数组P[0...m-1],是否存在i,使得SiSi+1... ...

  3. 4种字符串匹配算法:KMP(下)

    回顾:4种字符串匹配算法:BS朴素 Rabin-karp(上) 4种字符串匹配算法:有限自动机(中) 1.图解 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R ...

  4. 字符串匹配算法KMP算法

    数据结构中讲到关于字符串匹配算法时,提到朴素匹配算法,和KMP匹配算法. 朴素匹配算法就是简单的一个一个匹配字符,如果遇到不匹配字符那么就在源字符串中迭代下一个位置一个一个的匹配,这样计算起来会有很多 ...

  5. 字符串匹配算法--KMP字符串搜索(Knuth–Morris–Pratt string-searching)C语言实现与讲解

    一.前言   在计算机科学中,Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个主文本字符串S内查找一个词W的出现位置.此算法通过运用对这个词在不匹配时本身就包含足够的信息 ...

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

    处理字符串的过程中,难免会遇到字符匹配的问题.常用的字符匹配方法 1. 朴素模式匹配算法(Brute-Force算法) 求子串位置的定位函数Index( S, T, pos). 模式匹配:子串的定位操 ...

  7. [Algorithm] 字符串匹配算法——KMP算法

    1 字符串匹配 字符串匹配是计算机的基本任务之一. 字符串匹配是什么?举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串& ...

  8. 字符串匹配算法——KMP、BM、Sunday

    KMP算法 KMP算法主要包括两个过程,一个是针对子串生成相应的“索引表”,用来保存部分匹配值,第二个步骤是子串匹配. 部分匹配值是指字符串的“前缀”和“后缀”的最长的共有元素的长度.以“ABCDAB ...

  9. KMP Algorithm 字符串匹配算法KMP小结

    这篇小结主要是参考这篇帖子从头到尾彻底理解KMP,不得不佩服原作者,写的真是太详尽了,让博主产生了一种读学术论文的错觉.后来发现原作者是写书的,不由得更加敬佩了.博主不才,尝试着简化一些原帖子的内容, ...

  10. 字符串匹配算法-kmp算法

    一原理: 部分转自:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html 字 ...

随机推荐

  1. Zepto Api参考

    zepto API参考 简介 Zepto是一个轻量级的针对现代高级浏览器的JavaScript库, 它与jquery有着类似的api. 如果你会用jquery,那么你也会用zepto. 设计目的 ze ...

  2. label 和 legend标签的用法

    label 和 legend标签的用法 label标准用法: 一般浏览器都支持 一般而言,label标签位于表单元素的前面或者后面,为控件提供说明文字 <label for="user ...

  3. java 如何得到ISO 8601 时间格式

    http://blog.csdn.net/brightleo/article/details/7457004 public class DateUtil { public static String  ...

  4. POJ 1743 Musical Theme(后缀数组+二分答案)

    [题目链接] http://poj.org/problem?id=1743 [题目大意] 给出一首曲子的曲谱,上面的音符用不大于88的数字表示, 现在请你确定它主旋律的长度,主旋律指的是出现超过一次, ...

  5. hdoj 2546 饭卡(0-1背包)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2546 思路分析:该问题为0-1背包问题的变形题:问题求余额最少,设开始的余额为V,则求得用V-5可以买 ...

  6. Ordering Tasks(拓扑排序+dfs)

    Ordering Tasks John has n tasks to do. Unfortunately, the tasks are not independent and the executio ...

  7. ZOJ 38727(贪心)

    这道题真心坑.越想越远  想的飞起来了. 最后纠结起后缀表达式的定义来了. 题意: 就是给你一个串 ,  让你用最少改动次数来实它变成一个合法的后缀表达式,  改动方式有两种, 一种是直接加入数字或者 ...

  8. linux内核之网络协议栈

    https://www.ibm.com/developerworks/cn/linux/l-ntflt/

  9. 经典mssql语句大全

    一.基础 1.说明:创建数据库CREATE DATABASE database-name 2.说明:删除数据库drop database dbname3.说明:备份sql server--- 创建 备 ...

  10. 仿36氪(iOS版附源代码)

    前言: 这是我2016年3月开始写的,利用课余时间全心投入的项目,本以为是凭着轻松愉悦的方式来学习的,中途遇到bug解决bug的时候,每天晚上几乎都是写到寝室关灯,还有一次使用Github不当写了五天 ...