1. 程式人生 > >KMP演算法解題模板(更新)

KMP演算法解題模板(更新)

/*
kmp演算法的主要作用在於對next陣列的運用,所以這裡只給出next陣列的模板
性質1:對於每一個長度len的子串,該子串的最小迴圈節為len-next[len]
性質2:kmp的next不斷向前遞迴的過程可以保證對於每一個當前字首,都有一段字尾與之對應
*/

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 1e6+5;
int Next[maxn];
char mo[maxn];
int n2;

void GetNext() {
    int i = 0, j = -1;

    while (i < n2) {
        if(j == -1 || mo[i] == mo[j]) {
            i++;
            j++;
            Next[i] = j;
        } else j = Next[j];
    }
    return;
}

int main() {
    cin >> mo;

    n2 = strlen(mo);
    Next[0] = -1;
    GetNext();

    return 0;
}
/*
kmp模板
題意就是求B串在A串中的第一次匹配的下標,(從1開始) 
str就是A,mo就是B
*/

#include<bits/stdc++.h>
using namespace std ;

const int maxn = 1e6+5;
int Next[maxn], n1, n2;
char str[maxn], mo[maxn];

void GetNext() {
    int i = 0, j = -1;

    while(i < n2) {
        if(j == -1 || mo[i] == mo[j]) {
            i++;
            j++;
            Next[i] = j;
        } else j = Next[j];
    }
    return;
}

int kmp() {
    int cnt = 0;
    int i = 0, j = 0;

    while(i < n1) {
        if(j == -1 || str[i] == mo[j]) {
            i++;
            j++;
        } else j = Next[j];              //next陣列尋找與當前字尾匹配最長的字首,省略不必要的查詢
        if(j == n2) return i - n2 + 1;   //首地址
    }
    return -1;
}

int main() {
    cin >> str >> mo;

    n1 = strlen(str);
    n2 = strlen(mo);
    Next[0] = -1;
    GetNext();
    cout << kmp() << endl;

    return 0;
}
/*
kmp模板
題意就是求B串在A串中的出現次數(可重疊 
str就是S,mo就是B
*/

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e6+5;
int Next[maxn], n1, n2;
char str[maxn], mo[maxn];

void GetNext() {
    int i = 0, j = -1;

    while(i < n2) {
        if(j == -1 || mo[i] == mo[j]) {
            i++;
            j++;
            Next[i] = j;
        } else j = Next[j];
    }
    return;
}

int kmp() {
    int cnt = 0;
    int i = 0, j = 0;

    while(i < n1) {
        if (j == -1 || str[i] == mo[j]) {
            i++;
            j++;
        } else j = Next[j];
        if(j == n2) {
            cnt++;
            j=Next[j];      //完成一次匹配,將j移動到最長的字首處,省略不必要的查詢
        }
    }
    return cnt;
}

int main() {
    cin >> str >> mo;

    n1 = strlen(str);
    n2 = strlen(mo);
    Next[0] = -1;
    GetNext();
    cout << kmp() << endl;

    return 0;
}
/*
kmp模板
題意就是求B串在A串中的出現次數(不可重疊 
str就是A,mo就是B
*/

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e6+5;
int Next[maxn], n1, n2;
char str[maxn], mo[maxn];

void GetNext() {
    int i = 0, j = -1;

    while (i < n2) {
        if (j == -1 || mo[i] == mo[j]) {
            i++;
            j++;
            Next[i] = j;
        } else j = Next[j];
    }
    return;
}

int kmp() {
    int cnt = 0;
    int i = 0, j = 0;

    while (i < n1) {
        if (j == -1 || str[i] == mo[j]) {
            i++;
            j++;
        } else j = Next[j];
        if (j == n2) {
            cnt++;
            j = 0;
        }
    }
    return cnt;
}

int main() {
    cin >> str >> mo;

    n1 = strlen(str);
    n2 = strlen(mo);
    Next[0] = -1;
    GetNext();
    cout << kmp() << endl;

    return 0;
}
/*
最小迴圈節 POJ 2406 Power Strings 
結論:如果len%(len-nxt[len])=0,那麼迴圈次數為len/(len-nxt[len]),否則為1
*/

#include <cstdio>
#include <cstring>
using namespace std;

char s[1000100];
int nxt[1000100];

void get_nxt(){
    int len = strlen(s);
    nxt[0] = -1;
    int i = 0, j = -1;

    while (i < len){
        if (j == -1 || s[i] == s[j]){
            i++, j++;
            nxt[i] = j;
        }
        else j = nxt[j];
    }
}

int main(){
    //freopen("in.txt", "r", stdin);
    while (scanf("%s", s)){
        int len = strlen(s);
        if (len == 1 && s[0] == '.')break;

        get_nxt();

        int ans = len % (len - nxt[len]) == 0 ? len / (len - nxt[len]) : 1;
        printf("%d\n", ans);

    }
    return 0;
}