LOJ 103

这道题目早就做了,然而当初没写题解,今天补上,作为第一篇OJ题解~

这题是一道模板题,说白了,就是考察你会不会KMP(看毛片)算法。当然像我这种菜鸡小白,做这题之前根本不会KMP,看到匹配吗,那就两个循环暴力匹配嘛~简单!然后就一遍又一遍的RTE、TLE或WA。然后,整个人就处于崩溃边缘(;´༎ຶД༎ຶ`)!求助同桌之后,得知暴力的话肯定会超过内存和时间限制,所以照同桌说的,去学了KMP。

学习资料:从头到尾彻底理解KMP(2014年8月22日版)

这是一篇CSDN博客,写得非常非常好,我这种菜鸡看完之后都会了(虽然花了一整天55555,笨呐!)。本文以下的代码段也来自这篇博客。

做完题之后,再反复思考代码,自己又有了一些感悟。

首先,对于KMP算法,要得到一个模式串(通俗的说就是较长的那个)的next数组,求next数组的代码是:

void GetNext(char p[],int next[]){
	int plen = strlen(p);
	next[0] = -1;
	int k = -1;
	int j = 0;
	while(j < plen){
		if(k == -1 || p[j] == p[k]){
			++k;
			++j;
			next[j] = k;
		}else{
		k = next[k];	
		}
	}
}

next数组中元素next[ i ](next[ 0 ] = -1人为规定除外)的含义就是:模式串中第 i 位字符之前的最长border的长度,或者说,前缀能和后缀能匹配(相同)的最大长度(特别说明的是这种匹配允许前缀后缀部分重叠)。

其中,if 部分就是为 next数组 赋值的过程,只有当 k为-1 或 p[ j ](后缀部分)和 p[ k ](前缀部分)匹配时,才能求得next数组的值。而else干的事情就是,当 p[ j ] 和 p[ k ]不匹配时,返回到k前面找k之前的子串中的最大匹配,不断递归,直到找到,或者回到 k = next [ 0 ] = -1时结束。(这么说都抽象,自己写一个字符串,按代码的步骤自己求一下next数组,感受一下,很快就明白什么意思了)

然后,就是利用next数组在模式串中找目标串(通俗的说就是比较短的那个)了,代码如下:

(103题目要求是返回目标串出现次数,要对那篇博客的代码稍作修改,下面贴出来的是我修改过后的代码)

int kmp(char s[],char p[]){
	int i = 0,j = 0;
	int slen = strlen(s),plen = strlen(p);
	int next[plen];
	GetNext(p, next);
	while(i < slen){
		if(j == plen) j = next[plen];
		if(j == -1 || s[i] == p[j]){
			i++;
			j++;
		}else{
			j = next[j];
		}
		if(j == plen) ++cnt;
	}
	return cnt;
}

其中s为模式串,p为目标串。那三个 if 还是从下往上解释好了。

第三个 if 干得事情很简单,就是当目标串匹配到末尾,也就是在模式串中找到目标串了,计数变量就+1。

然后,第二个 if 就是匹配的过程了,如果找到了,就 i 和 j 都+1,即移动到下一个位置;否则,不匹配的话,就要利用目标串的next数组,找前缀中是否有匹配子串。所以整个过程中 i 始终不返回,而 j 利用next数组能做到返回到最大border的位置,不需要像暴力匹配那样,一不匹配就返回目标串的首位置,大大提升了效率。

最后,第一个 if 就是当找到一个目标串后,要继续接着找目标串,那么就不用返回到目标串得第一个位置,而是利用目标串的next数组,找到最大border的位置,并返回那里。

—————————————————————————————————————————————————————

完。根据上面两段代码,然后自己去把需要的变量、数组什么的定义一下,输入输出再写一下,就好了。最后,一个细节是,大小比较大的数组开成全局,否则会爆的......

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值