本期讲讲KMP算法,也就是江湖俗称的看毛片算法。前端
这个算法其实在面试中出现的几率仍是蛮大的,无论是校招仍是社招,甚至在考研中也遇到过,并且KMP算法也比较难理解,因此颇有必要研究一下。面试
先说一下这个算法出现的背景,也就是解决什么问题。每一个算法和框架都有它出现的缘由和要解决的问题,不少时候你不会一个技术,并非你笨,而是你没有找到它的使用场景或者是没搞明白它要解决的问题而已。因此,了解它要解决的问题,是学习的重中之重。算法
首先看一个例子:数组
字符串str="abcabcabcde",字符串match="abcabcde"若是str包含子串match,返回match在str中的起始位置。框架
这个问题其实可使用暴力来破解,以下图:学习
从str[i]开始(i初始等于0),每次只要遇到了match和str不匹配的状况,str回退到str[i+1],再继续str[i+1]和match[0]依次对比,久而久之,直到match彻底匹配出来或者str遍历完毕为止,这样作的时间复杂度是O(M*N),M是str的长度,N是match的长度。spa
那么有没有种方法能够不这么笨拙的解决字符串匹配的问题呢?3d
KMP算法就是解决match和str在匹配过程当中不停的作回退的问题的。简单一句话,KMP算法是作字符串高效匹配的算法code
说KMP的解法以前,先看看一个聪明的人类是如何解决这个问题的:blog
这样作的缘由是不必一次性退回从match[0]和str[1]开始比较,由于能够看出来绿色框内的match[0,1,2]和str[3,4,5]是重合的,重合的这部分彻底能够复用,没有必要再从match[0]和str[1]开始重复比较;
具体的过程能够模拟抽象成下图:
因此问题转化成了:
每次str[j]和match[j]不相同时,在match[0...j-1]这段字符串中,以match[j-1]结尾的后缀子串(不能包含match[0])和以match[0]开头的前缀子串(不能包含match[j-1])的最大匹配长度是多少?只要求出这个最大匹配长度,就能在str[j]和match[j]不相同时,知道把match滑动到什么位置了!
KMP算法的重点就是维护一个数组,保存match中每一个字符在不匹配时,match应该滑动到什么位置,这个数组起名叫next。
那么如何构造next数组呢?
首先对于match[0]来讲,它前面没有字符,因此next[0]规定为-1;对于match[1]来讲,由于next数组规定计算的时候子串后缀不能包含第一个字符,因此next[1]=0;
说完特殊状况,再说说常规状况,好比如今假设match[i]是A字符,match[i-1]是B字符,能够经过next[i-1]获得B字符前的字符串最长前缀与后缀的匹配区域,如今假设L为最长前缀子串,K为最长后缀子串,C为最长前缀子串以后的一位字符,如今只须要比较C和B便可
/** * @param {string} haystack * @param {string} needle * @return {number} */ var strStr = function(str, match) { if(str === null || match === null || match.length > str.length) return -1; if(str === "") return 0; let index1 = 0; let index2 = 0; let nextArr = getNext(match); console.log(nextArr); while(index1 < str.length && index2 < match.length) { if(str[index1] === match[index2]) { index1++; index2++; } else if(nextArr[index2] === -1) { index1++; } else { index2 = nextArr[index2]; } } return index2 === match.length ? index1 - index2 : -1; }; var getNext = function(match) { let next = [-1, 0]; let cn = 0; let index = 2; while(index < match.length) { if(match[index-1] === match[cn]) { cn++; next[index] = cn; index++; } else if(cn > 0) { cn = next[cn]; } else { next[index] = 0; index++; } } return next; }