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;
}
内容概要:本文档定义了一个名为 `xxx_SCustSuplier_info` 的视图,用于整合和展示客户(Customer)和供应商(Supplier)的相关信息。视图通过连接多个表来获取组织单位、客户账户、站点使用、位置、财务代码组合等数据。对于客户部分,视图选择了与账单相关的记录,并提取了账单客户ID、账单站点ID、客户名称、账户名称、站点代码、状态、付款条款等信息;对于供应商部分,视图选择了有效的供应商及其站点信息,包括供应商ID、供应商名称、供应商编号、状态、付款条款、财务代码组合等。视图还通过外连接确保即使某些字段为空也能显示相关信息。 适合人群:熟悉Oracle ERP系统,尤其是应付账款(AP)和应收账款(AR)模块的数据库管理员或开发人员;需要查询和管理客户及供应商信息的业务分析师。 使用场景及目标:① 数据库管理员可以通过此视图快速查询客户和供应商的基本信息,包括账单信息、财务代码组合等;② 开发人员可以利用此视图进行报表开发或数据迁移;③ 业务分析师可以使用此视图进行数据分析,如信用评估、付款周期分析等。 阅读建议:由于该视图涉及多个表的复杂连接,建议读者先熟悉各个表的结构和关系,特别是 `hz_parties`、`hz_cust_accounts`、`ap_suppliers` 等核心表。此外,注意视图中使用的外连接(如 `gl_code_combinations_kfv` 表的连接),这可能会影响查询结果的完整性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值