【模板】KMP

大佬的字符串讲解

废稿

\(KMP\)与前缀函数\(prefix(n)\)

#include <bits/stdc++.h>
using namespace std;
const int z = 65536;
int prefix[z];
void get_prefix(char *key) {
	int l = strlen(key);
	for(int i = 1, j;i < l;++i) {
		j = prefix[i-1];
		while(j > 0&&key[i] != key[j]) 
			j = prefix[j-1];
		if(key[i] == key[j]) ++j;
		prefix[i] = j;
	}
}//前缀函数计算;
int first_match(char *txt,char *key) {
	get_prefix(key);
	int len_key = strlen(key);
	int len_txt = strlen(txt);
	for(int i = 0, j = 0;i < len_txt;++i) {
		while(j > 0&&txt[i] != key[j]) 
			j = prefix[j];
		if(txt[i] == key[j])
			++j;
		if(j == len_key) 
			return i-j+1;
	}
	return -1;
}//查询key在txt中的第一次出现;
int count_match(char *txt,char *key) {
	get_prefix(key);
	int ans = 0;
	int len_key = strlen(key);
	int len_txt = strlen(txt);
	for(int i = 0, j = 0;i < len_txt;++i) {
		while(j > 0&&txt[i] != key[j]) 
			j = prefix[j];
		if(txt[i] == key[j]) 
			++j;
		if(j == len_key) {
			++ans;
			j = prefix[j];
		}
	}
	return ans;
}//查询key在txt中出现的次数;
char key[z], sig;
int KMP() {
	sig = 32;
	int i, j;
	int ans = 0;
	scanf("%s",key);
	int len = strlen(key);
	key[len++] = '#';
	for(i = 1;i < len;++i) {
		j = prefix[i-1];
		while(j > 0&&key[i] != key[j]) 
			j = prefix[j-1];
		if(key[i] == key[j]) 
			++j;
		prefix[i] = j;
	}
	while(sig == 10||sig == 32) 
		sig = getchar();
	for(;sig != 10&&sig != 32;sig = getchar()) {
		while(j > 0&&sig != key[j]) 
			j = prefix[j-1];
		if(sig == key[j]) 
			++j;
		if(j == len-1) 
			ans++;
	}
	return ans;
}//KMP算法;
int round(char *key) {
	get_prefix(key);
	int len = strlen(key);
	if(len%(len-prefix[len-1]) == 0) 
		return len-prefix[len-1];
	else return 0;
}//字符串的周期;
int times[z];
void pre_times(char *key) {
	get_prefix(key);
	int len = strlen(key);
	for(int i = 0;i < len;++i) 
		times[prefix[i]]++;
	for(int i = len-1;i > 0;--i) 
		times[prefix[i-1]] += times[i];
	for(int i = 0;i <= len;++i) 
		times[i]++;
}//每个前缀出现的次数;
signed main() {
	//to do;
}

\(\text{优化的}KMP\text{自动机}\)

int prefixed[z];
void get_prefixed(char *pattern) {
	int i = 1, j = -1;
	int len = strlen(pattern);
	prefixed[0] = -1;
	for(;i < len;++i) {
		while(j != -1&&pattern[i] != pattern[j+1]) 
			j = prefixed[j];
		if(pattern[i] == pattern[j+1]) 
			++j;
		if(j == -1||pattern[i+1] != pattern[j+1]) 
			prefixed[i] = j;
		else 
			prefixed[i] = prefixed[j];
	}
}
char sig, pattern[z];
int KMP() {
	sig = 32;
	getstr(pattern);
	int len = strlen(pattern), ans = 0, j = -1;
	get_prefixed(pattern);
	while(sig == 10||sig == 32) 
		sig = getchar();
	for(;sig != 10&&sig != 32;sig = getchar()) {
		while(j != -1&&sig != pattern[j+1]) 
			j = prefixed[j];
		if(sig == pattern[j+1]) 
			++j;
		if(j == len-1) {
			ans++;
			j = prefixed[j];
		}
	}
	return ans;
}

注意这里的prefixed已经不是前缀数组了,而是更优跳转位置
麻了,KMP自动机打不过自动机,Kuguya真NB
最后define了getchar,到了16ms,赶过去了(

\(2022.06.08:redo\)

\(Z\ Algorithm\)\(Z\)函数

int z[size];
void get_z(char *key) {
	int len = strlen(key);
	for(int i = 1, l = 0, r = 0;i < len;++i) {
		if(i <= r&&z[i-l] < r-i+1) 
			z[i] = z[i-1];
		else {
			z[i] = max(0,r-i+1);
			while(i+z[i] < len&&key[z[i]] == key[i+z[i]]) 
				++z[i];
		}
		if(i+z[i]-1 > r) {
			l = i;
			r = i+z[i]-1;
		}
	}
}
#include "bits/stdc++.h"
using namespace std;
const int z = 1024;

char a[z], b[z];
int prefix[z];

void get_prefix(char *key) {
	int l = strlen(key);
	for(int i = 0, j;i < l;++i) {
		j = prefix[i-1];
		while(j > 0&&key[i] != key[j]) 
			j = prefix[j-1];
			//if match is failed,
			//jump to the second length;
		//After matching :
		//if(success) key[i] == key[j] => prefix[i] = j+1;
		//else j == 0 => prefix[i] = (key[i] == key[j]);
		if(key[i] == key[j]) ++j;
		prefix[i] = j;
	}
}
int first_match(char *key,char *txt) {
    int lk = strlen(key), lt = strlen(txt);
    for(int i = 0, j = 0;i < lt;++i) {
        while(j > 0&&txt[i] != key[j]) 
            j = prefix[j];
        if(txt[i] == key[j])
            ++j;
        if(j == lk) 
        	return i-j+1;
    }
}
int count_match(char *key,char *txt) {
    int ans = 0;
    int lk = strlen(key), lt = strlen(txt);
    for(int i = 0, j = 0;i < lt;++i) {
        while(j > 0&&txt[i] != key[j]) 
            j = prefix[j];
        if(txt[i] == key[j])
            ++j;
        if(j == lk) {
            ++ans;
            j = prefix[j];
        }
    }
    return ans;
}
int main() {
	scanf("%s %s",a,b);
	get_prefix(b);
	printf("%d %d\n",first_match(b,a),count_match(b,a));
}

@bikuhiku

posted @ 2022-06-05 21:00  bikuhiku  阅读(3)  评论(0编辑  收藏  举报