找出字符串中第一个匹配项的下标。
KMP思想:寻找匹配的字符串,记录一部分之前匹配过的内容(前缀表),当匹配不成功时,避免从头开始重新匹配,节省时间。
获取前缀表(prefix table, 不向右移动,不全体减一):
字符串下标:0 1 2 3 4 5
字符串: a a b a a f
next(前缀表):0 1 0 1 2 0
i指向后缀的最后一个字符,j指向前缀的最后一个字符;
i = 1; j = 0; j++; next[i] = j; next[1] = 1;
i = 2; j = 1; j = next[j -1](回退); j = 0; next[2] = 0;
i = 3; j = 0; j++; next[3] = 1;
i = 4; j = 1; j++; next[4] = 2;
i = 5; j = 2; j = next[j -1]; j = 1; next[5] = 1????
啊啊啊啊啊啊啊啊啊啊,我需要再看几遍。他妈的没完全搞懂。
void getNext(int* next, const string& s) { //获取前缀表
// 1.初始化
int j = 0; // i指向字符串后缀的最后一个字符,j指向字符串前缀的最后一个字符
next[0] = 0;
//
for (int i = 1; i < s.size(); i++)// i从1开始
{
// 2.当i和j不匹配时,回退一位,看next数组中的前一位(连续的过程,使用的是while而非if)
while (j > 0 && s[i] != s[j]) {// j>0,因为下面有取j-1位置的数组下标元素
j = next[j - 1];// 找前一个位置进行回退
}
// 3.当i和j匹配的时候
if (s[i] == s[j]) {
j++;
}
// 4.更新next数组的值
next[i] = j;
}
}
int strStr(string haystack, string needle) {
if (needle.size() == 0)//如果待匹配的字符串长度为0
{
return 0;
}
int next[needle.size()];
getNext(next, needle);
int j = 0;
for (int i = 0; i < haystack.size(); i++)
{
while (j > 0 && haystack[i] != needle[j]) {
j = next[j - 1];
}
if (haystack[i] == needle[j])
{
j++;
}
if (j == needle.size())
{
return(i + 1 - needle.size());
}
}
return -1;
}