主页有其他数据结构内容(持续更新中)
难度:Easy
代码:
class Solution {
public:
// 构造next数组
void getNext(int* next, const string& s) {
int j = 0;
next[0] = 0; // 0号位置出错只能回到0号
for(int i = 1; i < s.size(); i++) {
// j是左指针,i是右指针
while (j > 0 && s[i] != s[j]) {
// j>0才能进入该循环,否则会出现数组下标非法的情况
// j-1是因为j位置已经不匹配了,而j-1是最后一个匹配的位置
j = next[j - 1];
}
if (s[i] == s[j]) {
j++;
// i++在循环结束自动做
}
next[i] = j;
// 但实际上由于向前看的规则,next数组的最后一位元素在匹配过程中永远不会被用到
// 即使是模式串最后一个元素匹配出错,跳转目标也是next[s.size - 1 - 1]
}
// 对传统next数组进行优化
// 由于next[s.size - 1]不会被调用,所以优化过程中也不会涉及到最后一位元素
int nextval[s.size()];
nextval[0] = 0;
for (int k = 1; k < s.size(); ++k) {
if (s[next[k - 1]] == s[k]){
// 如果即将跳转的目标下标所对应的字符和当前字符相同,就会出现无效跳转
// 优化的目的是确保不出现无效跳转
if (next[k - 1] == 0){
// 如果当前跳转的目标下标已经为0,则无需再向前看,防止出现数组下标非法
nextval[k - 1] = next[next[k - 1]];
}
else{
nextval[k - 1] = next[next[k - 1] - 1];
}
}
else{
// 若不存在无效跳转则保持不变,直接对应即可
nextval[k - 1] = next[k - 1];
}
}
// 将nextval数组复制给next数组
for (int p = 0; p < s.size(); ++p) {
next[p] = nextval[p];
}
}
// KMP字符串匹配
int strStr(string haystack, string needle) {
if (needle.size() == 0) {
// 如果模式串为空串就返回0
return 0;
}
int next[needle.size()];
// 构造next数组
getNext(next, needle);
int j = 0;
for (int i = 0; i < haystack.size(); i++) {
// 双指针,i是原字符串的指针,j是模式串的指针
while(j > 0 && haystack[i] != needle[j]) {
// j>0才能进入该循环
// j-1是因为j位置已经不匹配了,而j-1是最后一个匹配的位置
j = next[j - 1];
}
if (haystack[i] == needle[j]) {
j++;
}
if (j == needle.size() ) {
// 已经匹配成功,最后一次的j++会让j移到下标为needle.size()的位置
return (i - needle.size() + 1);
}
}
// 未发现匹配的字符串就返回-1
return -1;
}
};