腾讯和阿里的笔试刚过去了,里面有很多题都很值得玩味的。之前Blog积累的很多东西,还要平时看的书,都有很大的帮助。这个深有体会啊!

例如,腾讯有一道算法题是吃香蕉(好邪恶的赶脚..),一次吃一根或者两根,50根香蕉可以有多少种吃法?当时我一看尼玛,不就是我之前总结过的:递归算法,JavaScript实现。里面的走楼梯的问题,我到现在还是记得的。(但是为了抗议我对卷纸的不专业性,我用CoffeeScript实现了算法...感觉可能会因此跪下。)然后就是有一道选择题,考的是Javascript的闭包陷阱,我一看尼玛,不是我之前总结过的:循环闭包的影响以及其解决方案。我也是一模一样用setTimeout去模拟的。简直不能再爽。当然,也不得不说,腾讯到最后也只有这两题和前端有一点联系。

相比之下,阿里就好很多了。虽然时间很紧,题目很多,但起码不会一抬眼全是熟悉的陌生人。印象比较深的是《Javascript设计模式》里的观察者模式,还有《Javascript高级程序设计》里的有关CookieUtil的。。但是,我有一题,完全不记得如何做了。那就是今天的主角,KMP算法!


上面扯淡完毕了。个人博客嘛,随心所欲啦。先给参考资料的地址:字符串匹配的KMP算法。这个是阮一峰老师的博文,算是写的很不错的了。想看生动形象的博文的同学可以直接移步过去。

那这个用于字符串匹配的KMP算法到底怎么用的呢。我们先看看需求:字符串A="BBCABCDABABCDABCDABDE"里如何快速匹配到a=“ABCDABD”。用伪代码来写这些步骤应该是这样的:

  1. 字符串的首位与子字符串的首位进行匹配,匹配失败,则字符串后移继续匹配。匹配成功,则字符串与子字符串一起后移,继续匹配。
  2. 继续匹配的过程中,最理想的状态便是从头到尾成功,然后匹配过程也就结束了。倘若中途有不匹配的,子字符串就要回滚。

问题来了:子字符串回滚到哪儿?若是回滚到匹配开始的下一位,那当然是可以的,只不过是做了很多的无用功。所以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实现的更多相关文章

  1. BF算法和KMP算法(javascript版本)

    var str="abcbababcbababcbababcabcbaba";//主串 var ts="bcabcbaba";//子串 function BF( ...

  2. 数据结构与算法JavaScript (五) 串(经典KMP算法)

    KMP算法和BM算法 KMP是前缀匹配和BM后缀匹配的经典算法,看得出来前缀匹配和后缀匹配的区别就仅仅在于比较的顺序不同 前缀匹配是指:模式串和母串的比较从左到右,模式串的移动也是从 左到右 后缀匹配 ...

  3. javascript实现KMP算法(没啥实用价值,只供学习)

    简单粗暴上代码 KMP的原理我就不讲了,想转过弯儿来不容易,建议大家先学会了怎么推导出next数组规律,然后准备两张纸,大纸上写上一行你要匹配的目标字符串,并分别写出位置编号,小纸上写上一行,也写上位 ...

  4. KMP算法用JavaScript实现

    KMP算法是字符串匹配的经典算法,简称 看毛片, 理论知识请直接看阮一峰老师的这篇文章,我看完文章之后尝试对算法进行了实现. 一句话总结KMP算法的核心思想:就是跳过已经对比的部分 而KMP算法的核心 ...

  5. 理解 KMP 算法

    KMP(The Knuth-Morris-Pratt Algorithm)算法用于字符串匹配,从字符串中找出给定的子字符串.但它并不是很好理解和掌握.而理解它概念中的部分匹配表,是理解 KMP 算法的 ...

  6. 简单有效的kmp算法

    以前看过kmp算法,当时接触后总感觉好深奥啊,抱着数据结构的数啃了一中午,最终才大致看懂,后来提起kmp也只剩下“奥,它是做模式匹配的”这点干货.最近有空,翻出来算法导论看看,原来就是这么简单(先不说 ...

  7. KMP算法

    KMP算法是字符串模式匹配当中最经典的算法,原来大二学数据结构的有讲,但是当时只是记住了原理,但不知道代码实现,今天终于是完成了KMP的代码实现.原理KMP的原理其实很简单,给定一个字符串和一个模式串 ...

  8. 萌新笔记——用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)

    前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成"* ...

  9. KMP算法实现

    链接:http://blog.csdn.net/joylnwang/article/details/6778316 KMP算法是一种很经典的字符串匹配算法,链接中的讲解已经是很明确得了,自己按照其讲解 ...

随机推荐

  1. CSS控制超链接

    一.伪类 CSS控制元素的某种状态---偽类(用于向某些选择器添加特殊的效果)    偽类的语法:元素标签 偽类名称{属性:属性值;} 二.超链接        a:link:未访问的链接       ...

  2. poj 3694 pku 3694 Network tarjan求割边 lca

    题意:给你一个连通图,然后再给你n个询问,每个询问给一个点u,v表示加上u,v之后又多少个桥.一个最容易想到的办法就是先加边找桥,加边找桥,这样可定超时.那么就可以缩点,因为如果一条边不是桥那么无论怎 ...

  3. 转:Entity Framework对NULL值的处理

    今天拿Entity Framework改写早期的一个项目,涉及到对NULL值处理的时候,遇到了点问题,就是如何查询数据库中某字段为NULL的记录,写了几个测试用的例子,然后用SQL Server Pr ...

  4. iso中第三方框架SDWebImage的使用步骤

    一.SDWebImage的使用 1.依赖的框架 * ImageIO.framework * MapKit.framework 2.UIImageView下载图片需要的头文件:UIImageView+W ...

  5. 菜鸟学习笔记4——jquery事件

    方法 描述 bind() 向匹配元素附加一个或更多事件处理器 blur() 触发.或将函数绑定到指定元素的 blur 事件 change() 触发.或将函数绑定到指定元素的 change 事件 cli ...

  6. PHP中括号“{}”的3个作用

    1,将多个独立语句合并为一个复合语句,例如“if .... else ....”中推荐如此使用. 2,在变量的间接引用中进行定界,避免歧义.例如“${$my_var[8]}”与“${$my_var}[ ...

  7. BPMN2新规范与Activiti5

    上世纪九十年代以后,随着WfMC联盟的成立,BPM市场群雄逐鹿如火如荼,工作流技术得到了突飞猛进的发展,其中IBM.Oracle等大型软件厂商在工作流领域各扯大旗割据一方.2011年BPMN2.0新规 ...

  8. yaf框架流程三

    路由的原理请看http://yaf.laruence.com/manual/yaf.routes.html这个链接 要点:路由的顺序是堆栈模式的,及最后添加的路由规则最优先.由上两篇可知,定义的第一条 ...

  9. Linux/Unix shell 监控Oracle告警日志(monitor alter log file)

    使用shell脚本实现对Oracle数据库的监控与管理将大大简化DBA的工作负担,如常见的对实例的监控,监听的监控,告警日志的监控,以及数据库的备份,AWR report的自动邮件等.本文给出Linu ...

  10. yeoman的学习

    官网地址:http://yeoman.io/ 什么是yeoman? 在上一篇博客已粗劣地提到yeoman的安装和验证.说白了,其实yeoman是生成代码和搭建框架的前端自动化工具.为了做到这些,yeo ...