什么是KMP 解法
KMP算法是一种字符串匹配算法,可以在 O(n+m) 的时间复杂度内实现两个字符串的匹配。可以做一些快速查找,比如你的名字是否出现在一大串名单中。
相对于普通循环的方法。KMP算法可以做到当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。提高效率
案例
案例
所谓字符串匹配,就是:“字符串 P 是否为字符串 S 的子串?如果是,它出现在 S 的哪些位置?” 其中 S 称为主串;P 称为模式串。
文本串S:aabaabaaf
模式串P:aabaaf
1.什么是前缀表?
首先要先知道什么是前缀,和后缀
什么是前缀?
前缀是包含首字母,不包含尾字母的所有子串。
模式串P:aabaaf的前缀有:
a
aab
aaba
aabaa
什么是后缀?
后缀是包含尾字母,不包含首字母的所有子串。
模式串P:aabaaf的后缀有:
f
af
aaf
baaf
abaaf
求模式串的最大相等前后缀长度
分析模式串P:aabaaf
a: 没有前后缀,长度为0
aa:相等最长前后缀为a,长度为1
aab:前缀为a、aa,后缀为b、ab,没有公共前后缀,长度为0
aaba:前缀为a、aa,aab,后缀为a、ba,aba,最长公共前后缀为a,长度为1。
aabaa:前缀为a、aa,aab,aaba、后缀为a、aa,baa,abaa,最长公共前后缀为aa,长度为2。
aabaaf:没有公共前缀,为0。
得到前缀表
模式串P:aabaaf
它的前缀表,就是对应的最大相等前后缀长度:
0 1 0 1 2 0
2.得到前缀表如何匹配?
模式串P:a a b a a f
前缀表: 0 1 0 1 2 0
找到最长公共前缀长度为2,刚好就是公共的长度,aa,那么刚好对应前面aa,从aa的后一位重新开始匹配。简而言之,对应模式串P下标为2,对应字母为b。
3.代码如何实现(求前缀表)?
步骤
1.初始化
2.前后缀不同的情况
3.前后缀相同的情况
4.更新next数组的值
// 方法一:前缀表使用减1实现
class Solution {
public void getNext(int[] next, String s){//初始化
int j = -1;1.
next[0] = j;
for (int i = 1; i<s.length(); i++){
// 2.前后缀不同的情况
while(j>=0 && s.charAt(i) != s.charAt(j+1)){
j=next[j];
}
//3.前后缀相同的情况
if(s.charAt(i)==s.charAt(j+1)){
j++;
}
next[i] = j; //更新next数组(就是前缀表数组)的值
}
}
public int strStr(String haystack, String needle) {
if(needle.length()==0){
return 0;
}
int[] next = new int[needle.length()];
getNext(next, needle);
int j = -1;
for(int i = 0; i<haystack.length();i++){
while(j>=0 && haystack.charAt(i) != needle.charAt(j+1)){
j = next[j];
}
if(haystack.charAt(i)==needle.charAt(j+1)){
j++;
}
if(j==needle.length()-1){
return (i-needle.length()+1);
}
}
return -1;
}
}
参考:代码随想录