记录自己初次手写KMP算法时的思路,思索良久,故记录,语言表达不准确或有错误的地方还望各位大佬指点。
KMP算法的核心在于构建next数组,下图为自己思考的几个例子,图中示例的是getNext中for循环那一段:
此处引用b站某大佬的一段话:
关于指针回溯求next的理解
求next过程实际上是dp(动态规划),只与前一个状态有关:
若不匹配,一直往前退到0或匹配为止
若匹配,则将之前的结果传递:
因为之前的结果不为0时,前后缀有相等的部分,所以index所指的实际是与当前值相等的前缀,可视为将前缀从前面拖了过来,就不必将指针从前缀开始匹配了,所以之前的结果是可以传递的。
#include<string>
#include<vector>
#include<iostream>
using namespace std;
class Solution {
public:
//使用数组存储下标
vector<int> getNext(string s)
{
vector<int> output;
int index = 0;
//让第一个字符指向-1
output.push_back(-1);
if (s.size() == 1) return output;
//图中演示的是for循环这一段
for (int i = 1; i < s.size(); i++)
{
output.push_back(index);
while (s[i] != s[index] && index != 0)
{
//当不相等时,将index指向当前数的next,如果指向的位置不是0,则表示他们还存在相同的前缀
//此操作直到s[i]与s[index]相等,此时,相同的前缀部分就是index(自身也是相等的,所以出循环需要index++)
//如果指向的位置指向0,则表示指向字符串的头部。
index = output[index];
}
if (s[i] == s[index]) index++;
}
return output;
}
int strStr(string haystack, string needle) {
vector<int> next = getNext(needle);
int j = 0;//指向needle
int i = 0;
for (;i<haystack.size() && j<needle.size();i++)//i指向haystack
{
while (haystack[i] != needle[j] && next[j] != -1)
{
j = next[j];
}
if (haystack[i] == needle[j])
{
j++;
}
}
if (j==needle.size())
{
return i - j ;
}
return -1;
}
};
int main()
{
string s = "aabaaac";
Solution s1;
vector<int> v1 = s1.getNext(s);
for (int i : v1) {
cout << i << " ";
}
cout << endl;
//s1.strStr("aabaaabaaac", "aabaaac");
}