kmp

KMP笔记

xdg想骗吃骗喝,奈何本人能力不足,没能实现他的愿望。(_)

所以开始恶补kmp,并写下心得?

  1. 实现功能

    实现两个字符串的区配,并实现相关功能。(目前遇到的情况有点少,以后多了一定补上。)

  2. 暴力区配法

    想到字符串区配,我相信绝大部分人想到的是暴力搜索法。即一个个字符串相区配。既然容易想,但也有弊端,比方说 超时 ,非常容易想到最坏的情况是一个字符串区配到最后才适配上。其复杂度是O(mn)。

    m是字符串a的长度,n是字符串b的长度。

    所以,我建议,在读题时,要注意题目中给予的范围。几千什么的还好说。一旦上百万甚至更多,用这个办法肯定会超时的。用时请三思。

你认为我会贴代码?
我相信你动动脑子肯定打出来了.
接下来才是重头戏.

3.kmp区配法

讲之前建议听一下B站一个大佬的讲解,可能要听3遍哦,因为我听了3遍才明白了其运行原理/(ㄒoㄒ)/~~

[汪都能听懂的KMP字符串匹配算法【双语字幕】](https://www.bilibili.com/video/av3246487?from=search&seid=17082105778854054822)

看完,你应该明白了kmp相对与暴力缺少了逐个区配,而是通过next[]数组来实现跳跃区配,正如视频中讲到的,在进行next[]标记的过程中时间复杂度为O(m),而在区配中一个个区配,并没有从头再来,只需要一次即可.所以他的时间复杂度是O(m+n). //(如果你不记得这话,建议亲再去看一遍(_))

码字不易, 以下内容是一位大佬写的核心.

[很详尽KMP算法(厉害)](https://www.cnblogs.com/ZuoAndFutureGirl/p/9028287.html)
  • 假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置
    • 如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++,继续匹配下一个字符;
    • 如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]。此举意味着失配时,模式串P相对于文本串S向右移动了j - next [j] 位。
      • 换言之,当匹配失败时,模式串向右移动的位数为:失配字符所在位置 - 失配字符对应的next 值,即移动的实际位数为:j - next[j],且此值大于等于1。

​ 很快,你也会意识到next 数组各值的含义:代表当前字符之前的字符串中,有多大长度的相同前缀后缀。例如如果next [j] = k,代表j 之前的字符串中有最大长度为k

​ 此也意味着在某个字符失配时,该字符对应的next 值会告诉你下一步匹配中,模式串应该跳到哪个位置(跳到next [j] 的位置)。如果next [j] 等于0或-1,则跳到模式串的开头字符,若next [j] = k 且 k > 0,代表下次匹配跳到j 之前的某个字符,而不是跳到开头,且具体跳过了k 个字符。

如果你对这些过程感到很熟悉的话,上面视频的大佬讲的基本也是这个过程.如果想加深记忆的话建议结合这一段再看一遍

那么,问题的关键来了,什么求next[]数组呢?

下面先来个表

[外链图片转存失败(img-ffaZU2rK-1568277584034)(C:\Users\91515\Desktop\20140725231726921.jpg)]

看出来了吧

那什么实现呢

不多说上代码(其过程是和上面视频的过程讲的差不多,不清楚过程的话可以再看一遍)

void findnext(){
	int len = strlen (s);
	int a=-1,b=0;
	next[0]=-1;//为啥不是0,0前进是1,那0的地位何在?
	for(b=0;b<len;){
		if(s[a]==s[b]||a==-1){//对比两个字符是否相等,若是则前进一位,并在相应的位置作下标注,要跳跃到的位置.
			a++;
			b++;
			next[b]=a;
		}else{//不适配时则后退都上一个字符中next[]所标记的位置
			a=next[a];
		}
	}
}

上样题

period

For each prefix of a given string S with N characters (each character has an ASCII code between 97 and 126, inclusive), we want to know whether the prefix is a periodic string. That is, for each i (2 <= i <= N) we want to know the largest K > 1 (if there is one) such that the prefix of S with length i can be written as A K ,that is A concatenated K times, for some string A. Of course, we also want to know the period K.

Input
The input consists of several test cases. Each test case consists of two lines. The first one contains N (2 <= N <= 1 000 000) – the size of the string S.The second line contains the string S. The input file ends with a line, having the
number zero on it.

Output
For each test case, output "Test case #" and the consecutive test case number on a single line; then, for each prefix with length i that has a period K > 1, output the prefix size i and the period K separated by a single space; the prefix sizes must be in increasing order. Print a blank line after each test case.

Sample Input

3
aaa
12
aabaabaabaab
0

Sample Output

Test case #1
2 2
3 3

Test case #2
2 2
6 2
9 3
12 4

这是一道经典题,题意是:给定一个长度为n的字符串s,求它的每个前缀的最短循环节

想一下,那不就是有一个相同的next[]下标,有几个吗,只需要把字符串遍历一遍就可以了

上代码

#include<cstdio>
#include<cstring>
using namespace std;
int next[1000000];
char s[1000000];
void findnext(){
	int len = strlen (s);
	int a=-1,b=0;
	next[0]=-1;
	for(b=0;b<len;){
		if(s[a]==s[b]||a==-1){
			a++;
			b++;
			next[b]=a;
		}else{
			a=next[a];
		}
	}
}
int main(){
	int a;
	int Case=1;
	while(~scanf("%d",&a)){
		if(a==0){
			break;
		}
		scanf("%s",&s);
		findnext();
		 printf("Test case #%d\n",Case);
		 Case++;
		for(int i=1;i<=a;i++){
			int ans=i-next[i];
			if((i%ans==0)&&next[i]>0){
				printf("%d %d\n",i,i/ans);
			}
		}
		printf("\n");	
	}
	return 0;
}
资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 在ASP.NET开发中,定时任务是一种常见功能,用于在固定时间间隔内执行特定操作,比如数据同步、清理缓存或发送通知等。以下是实现ASP.NET定时任务的详细步骤和关键要点: ASP.NET定时任务通常通过System.Threading.Timer或System.Timers.Timer实现,二者都能周期性触发事件。在ASP.NET中,可以利用后台线程或HttpApplication生命周期事件来启动定时器。 System.Threading.Timer:适合在独立线程上运行任务,避免阻塞主线程,适合轻量级任务。 System.Timers.Timer:在多线程环境下,它会自动管理线程,更适合服务器端复杂任务。 创建定时器对象,设置Interval属性为10000毫秒(10秒),并注册Elapsed事件。该事件会在每个时间间隔结束时触发。 在Elapsed事件中编写要执行的代码,确保代码执行效率高,避免阻塞,因为长时间运行的任务可能影响其他请求。 通过Timer.Start()启动定时器,Timer.Stop()停止定时器。在ASP.NET中,可以在Application_Start和Application_End事件中控制定时器的启动和停止,确保服务器启动时定时器开始运行,关闭时停止。 在多用户环境下,如果定时任务会修改共享状态,必须考虑线程安全问题,可以使用锁或其他同步机制来确保数据一致性。 将应用程序部署到IIS时,需设置应用程序池的回收策略,避免定时任务因应用程序回收而中断。同时,确保IIS配置支持长时间运行的请求。 为定时任务添加日志记录非常重要,可以帮助排查问题并监控任务执行情况。 定时任务过于频繁可能会影响服务器性能,进而影响其他请求的响应时间。可根据需求调整时间间隔,或
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值