腾讯和阿里的笔试刚过去了,里面有很多题都很值得玩味的。之前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");

最新文章

  1. 面试web前端开发,被打击了
  2. Java语言编码规范(Java Code Conventions)
  3. VS2010插件及快捷键设置
  4. 利用RunTime解决由NSTimer导致的内存泄漏
  5. MVC 文件上传和图片剪辑
  6. Unity4.3.3 烘焙踩坑
  7. 【代码优化】坚持使用Override注解
  8. Spring各种注解标签作用详解
  9. hdu 1076
  10. Visual Studio/vs2013 正忙
  11. python学习之路前端-HTML
  12. S0.1 【转】调色板
  13. 修改Macros的值
  14. 【原创】研发应该懂的binlog知识(上)
  15. HTML查漏补缺 【未完】
  16. URI/URL/URN的联系和区别
  17. CSS自定义样式
  18. UVA 10303 - How Many Trees?(数论 卡特兰数 高精度)
  19. android-sdk和api版本
  20. BZOJ 3101: N皇后 构造

热门文章

  1. JS function的定义方法,及function对象的理解。
  2. R语言实现数据集某一列的频数统计——with和table
  3. 如何拷贝CMD命令行文本到粘贴板
  4. django - raw sql - 注意点!
  5. 关于ios越狱开发的那些事
  6. centos安装新版的nginx与php,添加memcahced扩展,测试memcached的json序列化
  7. 【英语】Bingo口语笔记(8) - 爆破音的发音技巧
  8. 【英语】Bingo口语笔记(61) - mind系列
  9. mac os 系统密码正确的 但是进不了系统
  10. 一天一点MySQL复习——存储过程