KMP算法——Javascript实现
腾讯和阿里的笔试刚过去了,里面有很多题都很值得玩味的。之前Blog积累的很多东西,还要平时看的书,都有很大的帮助。这个深有体会啊!
例如,腾讯有一道算法题是吃香蕉(好邪恶的赶脚..),一次吃一根或者两根,50根香蕉可以有多少种吃法?当时我一看尼玛,不就是我之前总结过的:递归算法,JavaScript实现。里面的走楼梯的问题,我到现在还是记得的。(但是为了抗议我对卷纸的不专业性,我用CoffeeScript实现了算法...感觉可能会因此跪下。)然后就是有一道选择题,考的是Javascript的闭包陷阱,我一看尼玛,不是我之前总结过的:循环闭包的影响以及其解决方案。我也是一模一样用setTimeout去模拟的。简直不能再爽。当然,也不得不说,腾讯到最后也只有这两题和前端有一点联系。
相比之下,阿里就好很多了。虽然时间很紧,题目很多,但起码不会一抬眼全是熟悉的陌生人。印象比较深的是《Javascript设计模式》里的观察者模式,还有《Javascript高级程序设计》里的有关CookieUtil的。。但是,我有一题,完全不记得如何做了。那就是今天的主角,KMP算法!
上面扯淡完毕了。个人博客嘛,随心所欲啦。先给参考资料的地址:字符串匹配的KMP算法。这个是阮一峰老师的博文,算是写的很不错的了。想看生动形象的博文的同学可以直接移步过去。
那这个用于字符串匹配的KMP算法到底怎么用的呢。我们先看看需求:字符串A="BBCABCDABABCDABCDABDE"里如何快速匹配到a=“ABCDABD”。用伪代码来写这些步骤应该是这样的:
- 字符串的首位与子字符串的首位进行匹配,匹配失败,则字符串后移继续匹配。匹配成功,则字符串与子字符串一起后移,继续匹配。
- 继续匹配的过程中,最理想的状态便是从头到尾成功,然后匹配过程也就结束了。倘若中途有不匹配的,子字符串就要回滚。
问题来了:子字符串回滚到哪儿?若是回滚到匹配开始的下一位,那当然是可以的,只不过是做了很多的无用功。所以KMP算法就是为了这个时候诞生的,可以有效的提高效率。
这里我用阮老师的一张图更好的解释一下。
我们可以看到,最佳的回滚位置应该是让子字符串的“C”对应空格。这样我们才可以最优化的处理重复的“AB”这个东西。
直接看一个公式:回滚位数 = 已匹配的字符数 - 对应的部分匹配值
。我们可以看到已经匹配的字符数是6,然后最佳的回滚位数是4,那么对应的部分匹配值应该是2,那这个2是怎么来的?
这就是KMP算法的精华。对于一个字符串:“ABCDABD”
- 前缀有:A,AB,ABC,ABCD,ABCDA,ABCDAB
- 后缀有:BCDABD,CDABD,DABD,ABD,BD,D
* "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。
所以我们最终只要观察到共有元素的最大长度,即可使用公式。那我们要实现这个算法,就要取得部分匹配表的算法和回滚算法。那我们看一下该如何实现。
var kmpGetPartMatchLen = function(str){
var partMatch = [];
for(var i = 0; i < str.length; i++){
var prefix = "",
suffix = "";
var newStr = str.slice(0, i + 1);
if(newStr.length <= 1){
partMatch[i] = 0;
}else{
//判断前后缀是否相同
for(var j = 0; j < i; j++){
prefix = newStr.slice(0, j + 1);
suffix = newStr.slice(-j - 1); //利用负参数尾巴开始取
if(prefix === suffix){
partMatch[i] = prefix.length;
}
}
//不存在检测
partMatch[i] = partMatch[i]? partMatch[i] : 0;
}
}
return partMatch;
};
上面这个是取出部分匹配表的算法的实现,然后接下来就是回滚算法的实现。
var kmp = function(sourceStr, subStr){
var partMatch = kmpGetPartMatchLen(subStr);
var result = false;
for(var i = 0; i < sourceStr.length; i++){
for(var j = 0; j < subStr.length; j++){
if(subStr.charAt(j) === sourceStr.charAt(i + j)){
if(j === subStr.length - 1){
result = true;
break;
}
}else{
//实现回滚,以subStr为参照物,即sourceStr往前移动
if(j > 0 && partMatch[j-1] >= 0){
//公式在此处实现
i += (j - 1 - partMatch[j-1] - 1);
}else{
break;
}
}
}
if(result) break;
}
if(result){
return i;
}else{
return -1;
}
};
那回到我们的笔试题,要实现手机号后四位在π中匹配的位置,那现在就是一句话的事情啦!
var π = "3.1415926.........."
kmp(π, "1092");
KMP算法——Javascript实现的更多相关文章
- BF算法和KMP算法(javascript版本)
var str="abcbababcbababcbababcabcbaba";//主串 var ts="bcabcbaba";//子串 function BF( ...
- 数据结构与算法JavaScript (五) 串(经典KMP算法)
KMP算法和BM算法 KMP是前缀匹配和BM后缀匹配的经典算法,看得出来前缀匹配和后缀匹配的区别就仅仅在于比较的顺序不同 前缀匹配是指:模式串和母串的比较从左到右,模式串的移动也是从 左到右 后缀匹配 ...
- javascript实现KMP算法(没啥实用价值,只供学习)
简单粗暴上代码 KMP的原理我就不讲了,想转过弯儿来不容易,建议大家先学会了怎么推导出next数组规律,然后准备两张纸,大纸上写上一行你要匹配的目标字符串,并分别写出位置编号,小纸上写上一行,也写上位 ...
- KMP算法用JavaScript实现
KMP算法是字符串匹配的经典算法,简称 看毛片, 理论知识请直接看阮一峰老师的这篇文章,我看完文章之后尝试对算法进行了实现. 一句话总结KMP算法的核心思想:就是跳过已经对比的部分 而KMP算法的核心 ...
- 理解 KMP 算法
KMP(The Knuth-Morris-Pratt Algorithm)算法用于字符串匹配,从字符串中找出给定的子字符串.但它并不是很好理解和掌握.而理解它概念中的部分匹配表,是理解 KMP 算法的 ...
- 简单有效的kmp算法
以前看过kmp算法,当时接触后总感觉好深奥啊,抱着数据结构的数啃了一中午,最终才大致看懂,后来提起kmp也只剩下“奥,它是做模式匹配的”这点干货.最近有空,翻出来算法导论看看,原来就是这么简单(先不说 ...
- KMP算法
KMP算法是字符串模式匹配当中最经典的算法,原来大二学数据结构的有讲,但是当时只是记住了原理,但不知道代码实现,今天终于是完成了KMP的代码实现.原理KMP的原理其实很简单,给定一个字符串和一个模式串 ...
- 萌新笔记——用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)
前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成"* ...
- KMP算法实现
链接:http://blog.csdn.net/joylnwang/article/details/6778316 KMP算法是一种很经典的字符串匹配算法,链接中的讲解已经是很明确得了,自己按照其讲解 ...
随机推荐
- bzoj4026
直接按照欧拉函数的计算方式来即可 φ=区间积*区间出现(质数-1)的积/区间出现过的质数的积 区间积是满足类似区间减法的操作的(利用逆元) 由于强制在线,上主席树就可以了(维护每个质数上次出现的位置p ...
- UVALive 3415 Guardian of Decency(二分图的最大独立集)
题意:老师在选择一些学生做活动时,为避免学生发生暧昧关系,就提出了四个要求.在他眼中,只要任意两个人符合这四个要求之一,就不可能发生暧昧.现在给出n个学生关于这四个要求的信息,求老师可以挑选出的最大学 ...
- JavaScript中Element与Node的区别,children与childNodes的区别
关于Element跟Node的区别,cilldren跟childNodes的区别很多朋友弄不清楚,本文试图让大家明白这几个概念之间的区别. Node(节点)是DOM层次结构中的任何类型的对象的通用名称 ...
- Mac 上安装MySQL
http://blog.neten.de/posts/2014/01/27/install-mysql-using-homebrew/ http://www.wkii.org/mac-os-x-ins ...
- linux上改变mysql数据文件的位置
用软连接改变了/var/lib/mysql的位置,并设置好mysql.mysql的权限,但是发现还是不能启动. 发现/var/log/mysqld.log 150308 16:16:02 [Warni ...
- vs2008破解方法
前提条件:测试操作系统WIN7 1,解压缩镜像文件 2,找到文件:Setup\setup.sdb,用记事本打开: 3,找到以下项: [Product Key]XPWKC7X98VKQDGM3QWYVG ...
- Java Web 乱码
1.mySql编码 2.jdbc编码 http://www.blogjava.net/NicholasEcho/archive/2008/11/03/238310.html ----- 1.HttpG ...
- 配置apache以fastcgi运行php
apache默认是用自带的mod_php模块运行php,现在我们介绍使用fastcgi来执行php脚本.先说下fastcgi的优点: Fastcgi的优点: 从稳定性上看, fastcgi是以独立的进 ...
- IPC_共享内存
在IPC(InterProcess Communication)的通信模式下,不管是使用消息队列还是共享内存,甚至是信号量,每个IPC的对象(object)都有唯一的名字,称为“键”(key).通过“ ...
- 数据绑定表达式(上):.NET发现之旅(一)
数据绑定表达式(上):.NET发现之旅(一) 2009-06-30 10:29:06 来源:网络转载 作者:佚名 共有评论(0)条 浏览次数:859 作为.NET平台软件开发者,我们频繁与各种各样的数 ...