28. 找出字符串中第一个匹配项的下标
题目链接:28. 找出字符串中第一个匹配项的下标
思路: 反复看了很久的视频。首先next是一个前缀表,模式串与前缀表对应位置的数字表示的就是:下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀。 如何构建一个前缀表呢,用i代表后缀的末尾,j代表前缀的末尾,j从第一个字符前的空字符开始(这样j可以从0开始,不用从1开始),i从第二个字符开始,如果i位置和j + 1位置不想等,j进行回退,回退到next[j],如果相等,j++,next[i] = j。
有了next表之后我们开始匹配,如果s[i] == p[j + 1]那么j++,如果不想等,j回退到next[j]。当j的值等于模式串的长度时,说明存在,坐标为i - 模式串的长度。
我的代码:
class Solution {
public int strStr(String haystack, String needle) {
if (needle.isEmpty()) return 0;
int n = haystack.length(), m = needle.length();
haystack = " " + haystack;
needle = " " + needle;
char[] s = haystack.toCharArray();
char[] p = needle.toCharArray();
int[] next = new int[m + 1];
getNext(next, p);
// 匹配过程
for (int i = 1, j = 0; i <= n; i++) {
while (j > 0 && s[i] != p[j + 1]) j = next[j];
if (s[i] == p[j + 1]) j++;
if (j == m) return i - m;
}
return -1;
}
// 构建过程
private void getNext(int[] next, char[] ch) {
for (int i = 2, j = 0; i < next.length; i++) {
while (j > 0 && ch[i] != ch[j + 1]) j = next[j];
if (ch[i] == ch[j + 1]) j++;
next[i] = j;
}
}
}
总结:
「KMP 匹配」过程: 首先匹配串会检查之前已经匹配成功的部分中里是否存在相同的「前缀」和「后缀」。如果存在,则跳转到「前缀」的下一个位置继续往下匹配。
跳转到下一匹配位置后,尝试匹配,发现两个指针的字符对不上,并且此时匹配串指针前面不存在相同的「前缀」和「后缀」,这时候只能回到匹配串的起始位置重新开始。