【2019杭电多校训练赛】1006-string matching 题解(e-kmp/扩展kmp)

原题链接:1006-string matching
在这里插入图片描述在这里插入图片描述在这里插入图片描述
其实这题的时间和内存给的很宽容,用e-kmp模版暴力就能过了,当然你直接用题目中的暴力匹配算法是会超时的(题目给了暴力那就当然不能用暴力啦)。

附上c++代码:

#include<stdio.h>
#include<string.h>
const int maxn = 1000005; //字符串长度最大值
long long next[maxn], ex[maxn]; //ex数组即为extend数组
char s[maxn];
//预处理计算next数组
void GETNEXT(char *str) {
	int i = 0, j, po, len = strlen(str);
	next[0] = len; //初始化next[0],因为从0开头就可以匹配整个T,故为len   /*与EXKMP代码不同处:无这句话*/
	while(str[i] == str[i + 1] && i + 1 < len) //计算next[1]  /*与EXKMP代码不同处:比较s1和s2*/
		i++;
	next[1] = i;/*与EXKMP代码不同处:ex[0]=i*/
	po = 1; //初始化po的位置  /*与EXKMP代码不同处:po = 0*/
	for(i = 2; i < len; i++) { /*与EXKMP代码不同处:i从1开始*/
		if(next[i - po] + i < next[po] + po) //第一种情况,可以直接得到next[i]的值  /*与EXKMP代码不同处:next[i-po]+i<ex[po]+po*/
			next[i] = next[i - po];/*与EXKMP代码不同处:ex[i]=next[i-po];*/
		else { //第二种情况,要继续匹配才能得到next[i]的值
			j = next[po] + po - i;/*与EXKMP代码不同处:j=ex[po]+po-i;*/
			if(j < 0)j = 0; //如果i>po+next[po],则要从头开始匹配
			while(i + j < len && str[j] == str[j + i]) //计算next[i]  /*与EXKMP代码不同处:i+j<len&&j<l2&&s1[j+i]==s2[j]*/
				j++;
			next[i] = j;/*与EXKMP代码不同处:ex[i]=j;*/
			po = i; //更新po的位置
		}
	}
}
//计算extend数组
void EXKMP(char *s1, char *s2) {
	int i = 0, j, po, len = strlen(s1), l2 = strlen(s2);
	GETNEXT(s2);//计算子串的next数组
	while(s1[i] == s2[i] && i < l2 && i < len) //计算ex[0]
		i++;
	ex[0] = i;
	po = 0; //初始化po的位置
	for(i = 1; i < len; i++) {
		if(next[i - po] + i < ex[po] + po) //第一种情况,直接可以得到ex[i]的值
			ex[i] = next[i - po];
		else { //第二种情况,要继续匹配才能得到ex[i]的值
			j = ex[po] + po - i;
			if(j < 0)j = 0; //如果i>ex[po]+po则要从头开始匹配
			while(i + j < len && j < l2 && s1[j + i] == s2[j]) //计算ex[i]
				j++;
			ex[i] = j;
			po = i; //更新po的位置
		}
	}
}
int main() {
	int T;
	while(~scanf("%d",&T)) {
		while(T--) {
			long long sum = 0;
			scanf("%s",s);
			EXKMP(s,s);//这个题目相当于自己和自己匹配
			for(int i=1; i<strlen(s); i++) {
				if(i + ex[i] == strlen(s)) {//检查是否到末尾
					sum += ex[i];
				} else
					sum += ex[i]+1;
				//printf("%lld %lld %d %lld\n",ex[i],i + ex[i],strlen(s),sum);
			}
			printf("%lld\n",sum);
		}
	}
	return 0;
}

最后附上暴力代码(会TLE),方便理解题意:

#include<iostream>
#include<string>
using namespace std;

int main(){
    int n;
    while(cin>>n){
        while(n--){
            string a;
            cin>>a;
            int sum=0;
            for(int i=1;i<a.length();i++){
                sum++;
                int first=0;
                int ii=i;
                while(a[first]==a[ii]&&ii<a.length()-1){
                    sum++;
                    first++;
                    ii++;
                }
            }
            cout<<sum<<endl;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43164778/article/details/98505343
今日推荐