一、简介
KMP 算法是用来求一个较长字符串是否包含另一个较短字符串的算法,其中难点在于求解 next 数组。
二、next 数组含义
next 数组含义为:如果匹配到该字符时失败,回溯的位置。
str | a | b | a | a | b | c | a | c |
---|---|---|---|---|---|---|---|---|
pos | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
next | -1 | 0 | 0 | 1 | 1 | 2 | 0 | 1 |
其中,next 数组首位设置为-1,意味着首位匹配失败时无法回溯。
三、next 数组求解
代码示例
string str = "abaabcac";
vector <int> next(str.size(), -1);
for (int i = 0, j = -1; i < next.size()-1; )
{
if (j==-1 || str[i]==str[j])
next[++i] = ++j;
else
j = next[j];
}
算法思想
从数组首地址开始遍历,判断以下情况:
-
如果 j 为 -1 , 意味此次若匹配失败时,必须回溯到串首 str[0] 开始匹配,在 next 数组下一位置中记下该值,接下来可以继续判断 str 字符串后置位。
-
如果 j 不为 -1 ,且匹配至 str[j] 成功,则此次若匹配失败从 j+1 开始匹配,在 next 数组下一位置中记下该值,接下来可以继续判断 str 字符串后置位。
-
如果 j 不为 -1 ,且匹配至 str[j] 失败,则找到 str[j] 位置匹配失败回溯位置,即令 j=next[j] 求得该回溯位置,并再次进行判断。此时意味着将 str[i] 位置字符替换 str[j] 位置字符,重新计算回溯。
如此,直到 next 数组被填满。
其中 j 起时值设置为 -1 ,是认为 str 首位匹配即失败,并避免 str[0]==str[0] 。
四、KMP 算法
代码示例
class Solution {
public:
int strStr(string haystack, string needle) {
if (needle.size() == 0)
return 0;
if (haystack.size() == 0)
return -1;
vector <int> next(needle.size(), -1);
for (int i = 0, j = -1; i < next.size()-1; )
{
if (j==-1 || needle[i]==needle[j])
next[++i] = ++j;
else
j = next[j];
}
for (int i = 0, j = 0; i < haystack.size(); )
{
if (j==-1 || haystack[i]==needle[j])
i++, j++;
else
j = next[j];
if (j == needle.size())
return i-j;
}
return -1;
}
};
算法思想
从首位置遍历 haystack 字符,判断是否匹配:
-
如果匹配,则后移 haystack 字符指针和 needle 字符指针,继续判断是否匹配。
-
如果不匹配,固定 haystack 字符指针不变,根据 next 数组移动 needle 字符指针。
直到遍历完 haystack 字符串(即失败)或者匹配到 needle 字符串末尾(即成功)。