KMP算法
2019-06-23 本文已影响0人
leo小超
字符串中找字串索引
暴破,直接处理从最开始匹配,从0-n开始循环查找,不相等重新计算
时间复杂度:O(n*m)
KMP算法处理找字符串中字串索引
如图:当"ABCDAB "失配时,直接移动到和"AB ABCD"处比较。
怎么知道移动位置?
失配处为D,D之前字符串为"ABCDAB",而"ABCDAB" 的前缀匹配为AB,那么"ABCDAB "字符串" "(空格)之前的2为"AB"和需要找的字符串"ABCDABD"的前2为一定相同。如果为0,则直接直接移动到空格处开始比较。
public Integer indexSubStr(String s, String subStr) {
int[] f = calculateTable(subStr);
int j = 0;
for (int i = 0; i < s.length(); ) {
if (s.charAt(i) == subStr.charAt(j)) {
j++;
if (j == subStr.length()) {
return i - (j - 1);
}
i++;
} else {
// 第一位没匹配成功,i++继续从j=0即字串第1位开始匹配
if (j == 0) {
i++;
} else {
// 有匹配成功的前缀,i不变,对齐匹配成功的前缀
// 匹配到"BBC ABCDAB "和"ABCDABD"时," "和"D"不等
// 但"D"前缀f[j-1]为2即"AB",i不动继续和"ABCDABD"前缀之后比较,即"BBC ABCDAB "的"AB "和"ABCDABD"的"ABC"比较
j = f[j - 1];
}
}
}
return -1;
}
关键计算前缀匹配表算法
思路
cacacabc
caca
caca
此时匹配成功,匹配+1
cacacabc
cacac
cacab
不匹配找更短的匹配串,cacac和cacab因为不匹配找更短的,即前缀cacac的更短的串caca和cacab更短的串,有相同更短的串caca。caca是已经匹配了的前缀,length = 4,而caca的匹配度等于匹配表中f[4-1]=f(3)位置
- 所以cacac匹配失效时,减少1个匹配度,即已经匹配了的caca的匹配度
- 如果cacac的串caca无匹配前缀即时匹配为0,表示cacab的前缀串caca无法和当前比较字符串匹配,结束,直接从失配处和子串第一位重新开始匹配;
- 如果cacac的caca前缀有匹配,那么假设匹配2位表示cacab和前缀caca也匹配2位即ca,那么比较第三位b和当前比较字符串第三位
- 如果匹配则匹配度是3位,即匹配为2+1=3,匹配到cab
- 如果不匹配则继续找前缀ca的前缀匹无匹配结束有匹配继续和b比较,如此匹配一直循环下去
public int[] calculateTable(String subStr) {
// 计算table
int[] f = new int[subStr.length()];
f[0] = 0;
int t = 0;
char temp;
for (int i = 1; i < subStr.length(); i++) {
temp = subStr.charAt(i);
if (temp == subStr.charAt(t)) {
f[i] = ++t;
} else {
while (t > 0) {
// 假设到b不匹配,b之前匹配度为caca即t,t=4
// 拿caca继续找匹配度(索引从0开始)t=f[t-1]=f[3]=2,s[t]=s[2]=c≠b
// 拿ca继续找t=f[t-1]=f[1]=0匹配度为0结束
t = f[t - 1];
if (t > 0) {
if (temp == subStr.charAt(t)) {
f[i] = ++t;
break;
}
}
}
}
}
return f;
}
借鉴
shortest-palindrome-solution中KMP图解
KMP算法详解 前面讲移动很清晰,讲计算table不结合KMP图解中的图看更清楚