KMP算法
名字的由来
是三个作者的名字缩写,没有特殊含义。
这篇文章是学习了邓俊辉老师的《数据结构与算法 c++》版本。
解决的问题
主要用于解决字符串串匹配的问题,例如在文本串 abcdefg 中寻找是否存在 cde 这个子串。
其中查找的目标字符串做模式串( pattern ),在文本串(text)中查找这个目标串,如果存在这个子串,就返回在文本串中第一次出现的下标,如果不存在就返回-1。
28. 实现 strStr()
暴力解法
暴力解法的思路很简单:
1)定义两个指针,分别用于遍历文本串和模式串。tIndex 和 pIndex 并且都初始化为 0
2)同时前进两个指针,如果对应的字符匹配就继续前进;如果不匹配,模式串指针回退到0。文本串指针回退到 i - j + 1。
3)退出循环。while (i < n && j < m)。n和m分别为文本串和模式串的长度
3.1)如果模式串索引超出边界,则意味着找到这个子串,匹配成功
3.2)如文本串索引超出边界,则意味着匹配失败
3.3)返回值。如果 i - j 小与等于 n - m ,说明匹配成功,并且i - j 就是匹配成功的位置,否则就是匹配失败。
class Solution {
public int strStr(String haystack, String needle) {
String text = haystack;
String pattern = needle;
if (text == null || pattern == null)
return -1;
int tIndex = 0;
int pIndex = 0;
while (tIndex < text.length() && pIndex < pattern.length()) {
if (text.charAt(tIndex) == pattern.charAt(pIndex)) {
tIndex++;
pIndex++;
}
else {
tIndex = tIndex - pIndex + 1;
pIndex = 0;
}
}
if (tIndex - pIndex > text.length() - pattern.length())
return -1;
return tIndex - pIndex;
}
}
暴力解法的缺点
暴力解法在匹配失败时,文本串回退到 i - j + 1,模式串回退到 0 。实际的复杂度是 O(n * m),但是暴力解法的框架是可以引出KMP算法的,只需要避免不必要的回退。
KMP 的思路
为了解决暴力解法在匹配失败时过多的回退。KMP的主要思路是:匹配失败时,文本串原地不动,模式串尽可能少的回退。
假设在 T[i] 和 P[j] 时匹配失败: