【2019杭电多校第五场1006=HDU6629】string matching

题意:
求一个字符串的所有后缀子串和原串的比较中要比较几次,才能得到最长公共前缀。

题解:扩展KMP裸题,用KMP推了2小时硬是没有弄出来,最后队友问我还有什么比较算法,突然想到还有扩展KMP然后百度了一下就直接过了。(谢队友不杀)听说还有用马拉车过的。。。。

PS:首先,所有的extend[i]+1,因为一个长度为N的串,那么其比较次数必然>=N。所有扩展KMP的extend[i]中,如果可以直接匹配到了后缀串最后一位字符,那么最后的结果不需要+1(因为不需要比较后一项来让其出错)。+1也只是用来最后凑成+N
关于extend的用处,可以百度扩展KMP来研究。

#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn = 1e6 + 7;
char str[maxn];
const int MAX = maxn; //字符串长度最大值
int knext[MAX], extend[MAX];

//预处理计算knext数组
void getknext(char str[])
{
	int i = 0, j, po, len = strlen(str);
	knext[0] = len; //初始化knext[0]
	while (str[i] == str[i + 1] && i + 1 < len) i++; knext[1] = i; //计算knext[1]
	po = 1; //初始化po的位置
	for (i = 2; i < len; i++)
	{
		if (knext[i - po] + i < knext[po] + po) //第一种情况,可以直接得到knext[i]的值
			knext[i] = knext[i - po];
		else //第二种情况,要继续匹配才能得到knext[i]的值
		{
			j = knext[po] + po - i;
			if (j < 0) j = 0; //如果i>po+knext[po],则要从头开始匹配
			while (i + j < len && str[j] == str[j + i]) j++; knext[i] = j;
			po = i; //更新po的位置
		}
	}
}

//计算extend数组
void EXKMP(char s1[], char s2[])
{
	int i = 0, j, po, len = strlen(s1), l2 = strlen(s2);
	getknext(s2); //计算子串的knext数组
	while (s1[i] == s2[i] && i < l2 && i < len) i++; extend[0] = i;
	po = 0; //初始化po的位置
	for (i = 1; i < len; i++)
	{
		if (knext[i - po] + i < extend[po] + po) //第一种情况,直接可以得到extend[i]的值
			extend[i] = knext[i - po];
		else //第二种情况,要继续匹配才能得到extend[i]的值
		{
			j = extend[po] + po - i;
			if (j < 0) j = 0; //如果i>extend[po]+po则要从头开始匹配
			while (i + j < len && j < l2 && s1[j + i] == s2[j]) j++; extend[i] = j;
			po = i; //更新po的位置
		}
	}
}
int main() {
	int t;
	cin >> t;
	while (t--) {
		memset(knext, 0, sizeof(knext));
		memset(extend, 0, sizeof(extend));
		scanf("%s", str);
		EXKMP(str, str);
		long long  sum = 0;
		int re = strlen(str);
		for (int i = 1; i <= re; i++) {
			sum += extend[i];
			if ((extend[i] + i) != re)
				sum++;
		}
		cout << sum << endl;
	}
	return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值