我所理解的 KMP(Knuth–Morris–Pratt) 算法
假设要在 haystack 中匹配 needle .
要理解 KMP 先需要理解两个概念 proper prefix 和 proper suffix,由于找到没有合适的翻译,暂时分别称真实前缀 和 真实后缀。
- 真实前缀(Proper prefix): 一个字符串中至少不包含一个尾部字符的前缀字符串。例如 "Snape" 的全部真实前缀是 “S”, “Sn”, “Sna”, and “Snap” .
- 真实后缀(Proper suffix): 一个字符串中至少不包含一个头部字符的后缀字符串。例如 “Hagrid” 的全部真实后缀是 “agrid”, “grid”, “rid”, “id”, and “d”.
KMP 的一个基本思想是:无论何时遇到匹配失败,我们已经匹配了一部分 needle 的字符串,它是 needle 的一个真实前缀,利用这个已匹配的真实前缀,我们可以避免重复匹配。如果想理解这个基本思想,可以参照 维基百科的例子 Knuth–Morris–Pratt algorithm example。
了解上面的基本思想后, 如何有效地利用 needle 的真实前缀信息?这个需要用一个数组 LofPS 记录。
LofPS[i] 表示 needle[0...i] 中既是真实前缀又是真实后缀的最长字符串长度。
上面这句话有点绕,但是仍然需要理解,因为无论少了那部分短语,意思都会不完整。
vector<int> LofPS; /**
* 求 s 中所有前缀字符串[0...i]各自的 既是真实前缀又是真实后缀的子字符串最长长度,存于 LofPS[i]。
*
* 例如令 len = LofPS[i],则表示 真实前缀s[0...len-1] 和 真实后缀s[ i-len+1...i ] 相等。
*
*/
vector<int> computePrefixSuffix(string s){ // LofPS[i] 表示 s[0....i] 部分中,既是真实前缀又是真实后缀的子字符串最长长度。
vector<int> LofPS(s.size()); if (s.size() == ) {
return LofPS;
} LofPS[] = ; int len = ;
int i = ; while (i < s.size()) { if (s[i] == s[len]) {
len++;
LofPS[i] = len;
i++;
continue;
} if (len != ) {
// 利用之前计算的结果。这里是一个需要理解的点。
// 根据已计算的 LofPS[len-1]部分 真实前缀、真实后缀的相等的最长长度,定位同样匹配 s 前缀但是更短的子字符串。
len = LofPS[len - ];
}else{
LofPS[i] = ;
i++;
}
} return LofPS;
} int KMPsearch(string haystack, string needle) { // 计算 needle 中所有前缀字符串[0...idx]各自的真实前缀且是真实后缀的最长长度。
vector<int> tmp(needle.size());
LofPS = tmp; LofPS = computePrefixSuffix(needle); int i = ;
int k = ; while (i < haystack.size() && k < needle.size()) {
if (haystack[i] == needle[k]) {
i++;
k++;
continue;
} if (LofPS[k-] != ) {
k = LofPS[k-];
continue;
} if (haystack[i] == needle[]) {
k = ;
i++;
}else{
k = ;
i++;
}
} if (k == needle.size()) {
return i - k;
}else{
return -;
}
}
参考资料:
Searching for Patterns | Set 2 (KMP Algorithm), geeksforgeeks
The Knuth-Morris-Pratt Algorithm in my own words, jBoxer
Worked example in Knuth–Morris–Pratt algorithm, wikipedia
我所理解的 KMP(Knuth–Morris–Pratt) 算法的更多相关文章
- 字符串匹配算法--KMP字符串搜索(Knuth–Morris–Pratt string-searching)C语言实现与讲解
一.前言 在计算机科学中,Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个主文本字符串S内查找一个词W的出现位置.此算法通过运用对这个词在不匹配时本身就包含足够的信息 ...
- knuth洗牌算法
首先来思考一个问题: 设计一个公平的洗牌算法 1. 看问题,洗牌,显然是一个随机算法了.随机算法还不简单?随机呗.把所有牌放到一个数组中,每次取两张牌交换位置,随机 k 次即可. 如果你的答案是这样, ...
- C前序遍历二叉树Morris Traversal算法
首先来递归算法,简单易懂: #include <stdio.h> #include <stdlib.h> #include <stdbool.h> typedef ...
- 关于SVM数学细节逻辑的个人理解(三) :SMO算法理解
第三部分:SMO算法的个人理解 接下来的这部分我觉得是最难理解的?而且计算也是最难得,就是SMO算法. SMO算法就是帮助我们求解: s.t. 这个优化问题的. 虽然这个优化问题只剩下了α这一个变 ...
- 理解Vue 2.5的Diff算法
DOM"天生就慢",所以前端各大框架都提供了对DOM操作进行优化的办法,Angular中的是脏值检查,React首先提出了Virtual Dom,Vue2.0也加入了Virtual ...
- 深入理解SVM,详解SMO算法
今天是机器学习专题第35篇文章,我们继续SVM模型的原理,今天我们来讲解的是SMO算法. 公式回顾 在之前的文章当中我们对硬间隔以及软间隔问题都进行了分析和公式推导,我们发现软间隔和硬间隔的形式非常接 ...
- KMP算法和bfprt算法总结
目录 1 KMP算法 1.1 KMP算法分析 1.2 KMP算法应用 题目1:旋转词 题目2:子树问题 2 bfprt算法 2.1 bfprt算法分析 2.2 bfprt算法应用 1 KMP算法 大厂 ...
- 深入理解Java虚拟机(三)、垃圾收集算法
1.第一门真正使用内存动态分配和垃圾收集技术的语言:Lisp 2.程序计数器.虚拟机栈.本地方法栈这3个区域随线程而生灭,这几个区域的内存会随着方法结束或线程结束而回收,GC关注的是Java堆和方法区 ...
- 深入理解java虚拟机【垃圾回收算法】
Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...
随机推荐
- 页面mask css
<html> <head> <style type="text/css"> .share_mask { position: fixed; top ...
- Html代码Font-Size中px与pt的区别
一个是设备坐标,一个是逻辑坐标,两者是不同的. px是个相对单位,一般像素的参考值为:在一个像素密度是90 pdi的显示器上,正常人从距离显示器28英寸处看一个像素的视角应该不小于0.0227度. 1 ...
- c#代码自动修改解决方案下任意文件
命名空间 using EnvDTE;using EnvDTE80; private DTE2 _applicationObject; public void AutoAddControl(插件 v_f ...
- 【 java版坦克大战--绘图技术】 绘制坦克
通过上一节,我们学会的用java绘图.那现在就用java绘制自己坦克. 首先通过分析坦克由这几部分组成.如图 各个部件的长宽如图.15,10为圆心. /** * 坦克游戏的1.0版 * 1.画出坦克 ...
- (转载)与OpenDialog相关的一个问题
OpenDialog的一个问题 有一个功能要求就是[每次打开文件的对话框的默认路径是上一次保存文件的路径],本来这个就是设置OpenDialog控件的InitialDir属性就行了,但是第一次打开的时 ...
- android 布局权重问题(转载)
//权重和父容器orientation有关 horizontal 指水平方向权重 android:layout_width vertical 指垂直方向权重 android:layout_he ...
- STM32学习内容和计划
一.STM32学习内容(流程) 1.学习STM32开发流程 ①MDK使用.建立工程.调试等 ②库开发方法 2.学习STM32常用外设开发 ①GPIO ②中断 ③定时器 ④串口 ⑤CAN 3.学习STM ...
- 将十进制的颜色制转换成ARGB
将一个十进制的颜色值转换成具体的ARGB 格式,起初,这看起来有些难,一直找不到方法,在网上也找不到具体的资料,最后在同事的指导下成功完成的转换,现分享出来,供大家参考,具体转换方法如下: /// & ...
- Marsonry
前言 1 MagicNumber -> autoresizingMask -> autolayout 以上是纯手写代码所经历的关于页面布局的三个时期 在iphone1-iphone3gs时 ...
- oracle 报“无效数字”异常和“ORA-01830: 日期格式图片在转换整个输入字符串之前结束”
1.问题1 执行下列SQL: sql = "select count(1) as totle from vhl_model_data a where a.OBTAIN_CREATE_TIME ...