fail数组定义:最长前后缀长度-1 如ababab为3 最长前后缀为4:abab(第一个) abab(第二个)
初始值为什么为-1:让第一个if的now + 1 = 0 否则会少判断第一个字母
怎么加速获得fail值:
如果不相等 那么仍可利用原来的最长前后缀
我们当然不想把这个长度缩小太多 因为我们要找的是最长相同前缀后缀 那么这个前缀必定会在子串A 后缀必定会在子串B(因为这两个子串完全相同)
同时 因为子串A的后缀与子串B的后缀相同 那么新最长相同前后缀长度等于子串A的最长相同前后缀长度 即 now = fail[now - 1](fail数组定义为最长相同前后缀长度的情况,下面的代码定义为长度-1所以有所不同),当终于P[now] = P[x]则可以向右扩展 或者始终不相等则从零开始
class Solution { public: bool kmp(const string& s){ int n = s.size(); //将fail定义为最长相同前后缀长度 - 1 vector<int> fail(n,-1); for(int i = 1; i < n; i++){ int now = fail[i - 1]; //如果初始值是-1 那么这里是now + 1 如果是0 这里是now 下面的赋值同理 while(now != -1 && s[now + 1] != s[i]){ //如果始终不同 那么始终缩短为a串的最长相同子前缀直到now为-1或者相同了 now = fail[now]; } //前一个fail值的下一位和当前位相同的话 当前fail为前fail+1 if(s[now + 1] == s[i]) fail[i] = now + 1; } //第一个条件:只有当原串有相同前后缀才有可能符合题意 //第二个条件:规律:最长规律字串长度 = n - 最长前后缀 成倍数 return fail[n - 1] != -1 && n % (n - fail[n - 1] - 1) == 0; } bool repeatedSubstringPattern(string s) { return kmp(s); } };
参考资料:知乎KMP回答