本文主要叙述用于字符串匹配的KMP算法。

  阮一峰的博文“字符串匹配的KMP算法"将该算法讲述得非常形象,可参考之。

字符串‘部分匹配值’计算

  KMP算法重要的一步在于部分匹配值的计算。模仿《算法导论》中的伪代码,对应的C++代码为:

 vector<int> partialMatching(string P)
{
int szP = P.size();
vector<int> pMatch;
pMatch.resize(szP);
// retVec[0] = 0;
int k = ;
for (int i = ; i < szP; i++)
{
while (k > && P[k] != P[i])
k = pMatch[k - ];
if (P[k] == P[i])
k = k + ;
pMatch[i] = k;
}
return pMatch;
}

  代码看起来挺简洁,但要理解起来就比较麻烦了。其中有一个问题就是:字符串“cabab”的部分匹配值为什么全都为0?其中的“ab”不是重复了吗,应该要算作重复的子串啊?

  之所以有这个困惑,是对字符串的前缀和后缀的概念不理解。在阮一峰的博文中,他提到"前缀"是指除了最后一个字符以外,一个字符串的全部头部组合;"后缀"指除了第一个字符以外,一个字符串的全部尾部组合。

  另外他还举了一个例子来说明如何求取一个字符串的部分匹配值:

    "部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。以"ABCDABD"为例,
      - "A"的前缀和后缀都为空集,共有元素的长度为0;
      - "AB"的前缀为[A],后缀为[B],共有元素的长度为0;
      - "ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;
      - "ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;
      - "ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A",长度为1;
      - "ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB",长度为2;
      - "ABCDABD"的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。

  注意:这个例子个人感觉如果没有好好理解,则有可能误解!阮一峰的做法是将一个字符串拆成不同长度的子串,然后求部分匹配值,而我们实际并不是这样子做的(参考上边代码),所以这些步骤可能会让我们误解后缀一定要以该字符串的最后一个字符来结束。

  对于一个字符串的前缀而言,一定要从第一个字符开始;而对其后缀而言,则不必要以最后一个字符结束。

KMP算法

  模仿《算法导论》中的伪代码,对应的C++代码为:

 vector<int> KMPMatching(string T, string P)
{
int szT = T.size();
int szP = P.size();
vector<int> pMatch = partialMatching(P);
vector<int> kmpMatch;
int k = ;
for (int i = ; i < szT; i++)
{
while (k > && T[i] != P[k])
k = pMatch[k - ]; if (T[i] == P[k])
k = k + ; if (k == szP - )
{
kmpMatch.push_back(i - k + );
k = pMatch[k - ];
}
}
return kmpMatch;
}

  注意,第19行的

k = pMatch[k - ];

  不能直接写成

k = ;

  例如待匹配字串为abababc,匹配模式为aba,则有两个符合匹配模式的子串:aba、aba,而中间的a是共享的。

"《算法导论》之‘字符串’":字符串匹配的更多相关文章

  1. 数据结构之 字符串---字符串匹配(kmp算法)

    串结构练习——字符串匹配 Time Limit: 1000MS Memory limit: 65536K 题目描述   给定两个字符串string1和string2,判断string2是否为strin ...

  2. 关于KMP算法理解(快速字符串匹配)

    参考:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html 2016-08- ...

  3. 【算法与数据结构】字符串匹配之KMP算法

    // KMP.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> #include < ...

  4. 实现字符串匹配的KMP算法

    KMP算法是Knuth-Morris-Pratt算法的简称,它主要用于解决在一个长字符串S中匹配一个较短字符串s. 首先我们从整体来把我这个算法的思想. 字符串匹配的朴素算法: 我们容易想到朴素算法, ...

  5. 字符串匹配KMP算法的讲解C++

    转自http://blog.csdn.net/starstar1992/article/details/54913261 也可以参考http://blog.csdn.net/liu940204/art ...

  6. 字符串匹配之KMP

    说明 KMP算法看懂了觉得特别简单,思路很简单,看不懂之前,查各种资料,看的稀里糊涂,即使网上最简单的解释,依然看的稀里糊涂. 我花了半天时间,争取用最短的篇幅大致搞明白这玩意到底是啥. 这里不扯概念 ...

  7. 算法导论 (Thomas H.Cormen / Charles E.Leiserson / Ronald L.Rivest / Clifford Stein 著)

    第一部分 基础知识 第1章 算法在计算中的作用 第2章 算法基础 第3章 函数的增长 第4章 分治策略 第5章 概率分析和随机算法 第二部分 排序和顺序统计量 第6章 堆排序 第7章 快速排序 第8章 ...

  8. hrbustoj 1551:基础数据结构——字符串2 病毒II(字符串匹配,BM算法练习)

    基础数据结构——字符串2 病毒IITime Limit: 1000 MS Memory Limit: 10240 KTotal Submit: 284(138 users) Total Accepte ...

  9. 字符串匹配--kmp算法原理整理

    kmp算法原理:求出P0···Pi的最大相同前后缀长度k: 字符串匹配是计算机的基本任务之一.举例,字符串"BBC ABCDAB ABCDABCDABDE",里面是否包含另一个字符 ...

随机推荐

  1. 自定义progressDialog(数据加载框)的实现

    大家在开发客户端时基本上都需要获取数据,在获取数据时会有一个等待状态,这时我们可以利用系统自带的progressDialog来向用户展示"数据正在加载中..."等等,但有时我们会觉 ...

  2. 操作系统服务:OS模块

    http://blog.csdn.net/pipisorry/article/details/52454486 一般的操作系统服务之OS模块Generic Operating System Servi ...

  3. Volley的基本使用

    Volley的基本使用 导入jar包 导入成功 源码 GET请求下载地址:http://download.csdn.net/detail/q4878802/9053969 POST请求下载地址:htt ...

  4. Java中for_each循环的使用

    最近在看一些和安卓相关的书籍,看到了for_each这种循环结构,这是为了简化java的for循环而改造的一种方便使用的格式. 格式如下: for(数据类型 变量:集合) 语句块 接下来看一个例程: ...

  5. Swift基础之集成单选按钮横竖两种样式

    最近马上放假所以比较忙,今天简单写一个项目中出现的单选按钮的横竖样式,PS:封装的是Swift语言样式 首先创建一个UIView的类,然后创建方法,最后调用类中的方法进行显示 //参数一:需要显示的内 ...

  6. 一步步创建Qt Widget项目+TextFinder案例(摘自笔者2015年将出的《QT5权威指南》,本文为试读篇)

     创建一个基于应用的QtWidget应用程序 这个手册描述了怎样使用QtCreater创建个一个小的Qt应用程序,Text Finder.它是Qt工具Text Finder例子的简写版本.这个应用 ...

  7. 学习Tensorflow,使用源码安装

    PC上装好Ubuntu系统,我们一步一步来讲解如何使用源码安装tensorflow?(我的Ubuntu系统是15.10) 安装cuda 根据你的系统型号选择相应的cuda版本下载 https://de ...

  8. ROS_Kinetic_20 ROS基础补充

    ROS_Kinetic_20 ROS基础补充 1 手动创建ROS功能包 参考官网:http://wiki.ros.org/cn/ROS/Tutorials/Creating%20a%20Package ...

  9. LCD 显示异常定位分析方法

    第一种情况: 进入kernel或android 后,如果LCM图像示异常,可以通过如下步骤来判断问题出现在哪个层面. step1:通过DMMS截图,来判断上面刷到LCM的数据是否有问题. 若DMMS获 ...

  10. 上海C++游戏服务器群活动PPT下载

    下载页面: http://download.csdn.net/download/jq0123/8227519 跨服与跨区的设计PPT 上海C++游戏服务器群 2014.11.9 沙龙讲义. 自我介绍 ...