KMP复习

KMP复习

kmp真的是一个好算法,将暴力\(O(nm)\)的匹配改进成了\(O(n+m)\)

nb!

推荐一个视频。

#include
using std::cin;
using std::cout;
using std::endl;
using std::string;
const int maxn = 1000005;
string s1, s2;
int next[maxn];

int main() {
    std::ios::sync_with_stdio(false);
    cin >> s1 >> s2;
    next[0] = 0;
    for(int i = 1, j = 0; i < s2.size(); i++) {
        while(j > 0 && s2[j] != s2[i]) j = next[j - 1];
        if(s2[j] == s2[i]) j++;
        next[i] = j;
    }
    for(int i = 0, j = 0; i < s1.size(); i++) {
        while(j > 0 && s2[j] != s1[i]) j = next[j - 1];
        if(s2[j] == s1[i]) j++;
        if(j == s2.size()) {
            cout << i - j + 2 << endl;
        }
    }
    for(int i = 0; i < s2.size(); i++) {
        cout << next[i] << ' ';
    }
    cout << endl;
}

这里是一道加深理解的kmp题:CF126B Password

题意:给你字符串,找到最长的既是前缀也是后缀还在中间出现过的子串长度。

这道题只需要用到kmp算法的next数组就能解决。

首先跑一遍kmp,如果整个字符串的next为0,就没有答案。

然后暴力地找最大前缀之后是否有next能大于等于其长度的,如果有就说明确实有满足题意的最长子串。(前缀与中间串是可以重叠的)

如果找不到,还可能有其他的答案,我们缩小至最长前缀的next值大小。如果不等于0,那就是答案,否则无解。

这道题告诉我们kmp中的next数组的含义非常丰富,加以利用可以线性地解决问题!

#include
using std::cin;
using std::cout;
using std::endl;
using std::string;
const int maxn = 1e6 + 5;
string str;
int next[maxn];
int main() {
    cin >> str;
    next[0] = 0;
    for(int i = 1, j = 0; i < str.size(); i++) {
        while(j > 0 && str[i] != str[j]) j = next[j - 1];
        if(str[i] == str[j]) j++;
        next[i] = j;
    }
    int k = next[str.size() - 1];
    if(k == 0) {
        puts("Just a legend");
        return 0;
    } 
    for(int i = k; i < str.size() - 1; i++) {
        if(next[i] >= k) {
            for(int i = 0; i < k; i++) cout << str[i];
            return 0;
        }
    }
    if(next[k - 1] == 0) {
        puts("Just a legend");
        return 0;
    }
    for(int i = 0; i < next[k - 1]; i++) {
        cout << str[i];
    }
    return 0;
}

转载于:https://www.cnblogs.com/Garen-Wang/p/11333269.html

你可能感兴趣的:(KMP复习)