KMP算法实现思路——附带Leetcode 1392最长快乐前缀和28实现strStr()的KMP解法 Java语言
目标问题
KMP算法主要用于解决字符串匹配相关等问题,实施起来简单,但是过程精巧。
如题在bacbababaabcbab
字符串中寻找abababca
字符串的位置。一般的思路会是从字符串头开始逐一匹配,再逐一滑动,如果不做任何剪枝,那么会多出很多多余计算。KMP算法即是一种字符串匹配暴力检索的一种剪枝算法。
KMP算法
创建部分匹配表
在进行KMP算法之前,我们首先需要创建一个辅助数组next[]
,长度为需要寻找的字符串的长度,内容则为从字符串起始点到该索引位置的子字符串([0,..,i]
)的部分匹配值。部分匹配值指该字符串的前缀和后缀最长的共有元素的长度(不包含本身)。以下是部分匹配表 数组next[]
的样例:
char a b a b a b c a
index 0 1 2 3 4 5 6 7
value 0 0 1 2 3 4 0 1
- "ab"的前缀有[a],后缀有[b],无匹配,值为0
- "abab"的前缀有[a,ab,aba],后缀有[b,ab,bab],最长匹配的值为ab,值为2
知道了部分匹配表的内容,那么如何创建一个部分匹配表呢?这个问题等同于Leetcode1392题最长快乐前缀
思路如下:
创建长度等同于字符串的数组next[]
for i from 1 to length - 1:
k = next[i - 1] //用k记录next[i - 1]即字符串[0-i-1]中最长前后缀匹配的长度
while(k > 0 && 字符串第k位不等同于第i位):
k = next[k - 1] // 如果第k位的数等同于第i位的数,那么next[i]就可以等于之前最长前后缀匹配的长度k加上1
// 但是如果不等于,next[i]就不是简单的为0,而是应该把k等于字符串[0, k-1]中最长前后缀匹配的长度,这里是因为
// 之前已经有k位匹配了,类似于1 2 1 4 1 2 1 2(i),之前已经有1 2 1匹配了,尽管第i位的2不等于4了,但是由于i位前面
// 的1 2 1是等同于开头的1 2 1,因此应该寻找1 2 1中的最长前后缀匹配的长度,另其为k。
// 如果此时字符串第k位等同于第i位,则中断循环; 如果不等同,则继续重复上面的步骤令k = next[k - 1]
if 字符串第k位等同于第i位 // 跳出循环要么k = 0了,要么第k位等于第i位了
next[i] = k + 1 // 等同的情况下,就像上面说的,直接赋值k + 1就行了
// k = 0的情况且k位不等于i位时,直接默认为0就行了,不需要操作
// 走完for循环,完成匹配表
代码附上Leetcode的1392题的解法:
class Solution {
public String longestPrefix(String s) {
int[] next = new int[s.length()];
for(int i = 1; i < s.length()