KMP演算法解題模板(更新)
阿新 • • 發佈:2018-12-24
/* 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;
}