寒假总结 2-8

复工复产第一天

 

【模板】KMP字符串匹配 - 洛谷

KMP算法分两步,一步是模式串(需要用于匹配的字符串)自己匹配时的处理,另一步就是模式串匹配目标串了。

模式串自己匹配自己时可以理解为对不同长度的自己找有最大公共长度的头尾(但是不能全部长度去匹配),来造出模式串的前缀数组

比如下面字符串

abcdabcdxabcdabcd

长度为7时,有

abcdabc

最大公共长度的头尾为abc

则当前数组为 

0 0 0 0 1 2 3

 长度为15时

abcdabcdxabcdab      

最大公共长度的头尾为abcdab            

则当前数组为

0 0 0 0 1 2 3 4 0 1 2 3 4 5 6

 如果把模式串拉更长也许能有更好的表现,例如下面(数据点5的模式串),但我懒(

CCBABBACBABCAACBBCAACCBACACCCACCABABBABBABCABCCABABBCCABABACBCCACBACACBABCCBAAAABBBCBBABCBABABBCABCB

 它的前缀数组是

0 1 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 1 0 0 1 2 3 4 1 0 1 2 2 0 1 2 0 0 0 0 0 0 0 0 0 0 1 0 0 1 2 0 0 0 0 0 1 2 0 0 0 0 0 1 0 1 2 0 1 0 0 1 0 1 0 0 0 1 2 3 4 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0

 反正就这么处理前缀数组了

int j = 0;
	for (int i = 2; i <= rr; i++) {
		while (j > 0 && b[i] != b[j + 1]) j = kmp[j];
		if (b[i] == b[j + 1])j++;
		kmp[i] = j;
	}

然后就是匹配,以j+1为模式串下标,i为目标串下标,每次匹配字符成功时共同进位,如果不成功就模式串下标向前寻找上一个“头”的“屁股”,这样可以保证回头找的时候每个“头”都与目标串在“头”长度之前的所有字符能够匹配,从而减少时间

之前啦个字符串

abcdabcdxabcdabcd

前缀数组为

0 0 0 0 1 2 3 4 0 1 2 3 4 5 6 7 8

假设他匹配的目标串当前是

abcdabcdxabcdax……

abcdabcdxabcdabcd

                          |->  j=14

此时j+1=15位无法匹配,则 j =数组[ j ]=5

变为

abcdabcdxabcdax……

                 abcdabcdxabcdabcd

                          |->  j=5

j+1=6,还是不行,重复上面操作,j=0,

j+1=1,还是匹配不上,溜了,让i++去(

j = 0;
	for (int i = 1; i <= ll; i++) {
		while (j > 0 && a[i] != b[j + 1]) j = kmp[j];
		if (a[i] == b[j + 1])j++;
		if (j == rr) {
			printf("%d\n", i - rr + 1);
			j = kmp[j];
		}
	}

 ps:输入字符串时地址+1是学习题解里的办法,自己用地址原位写,try了半天没整出来

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<malloc.h>
char a[1000009], b[1000009];
int kmp[1000009] = {0};
int main() {
	scanf("%s%s", a + 1, b + 1);
	int ll = strlen(a + 1), rr = strlen(b + 1);
	int j = 0;
	for (int i = 2; i <= rr; i++) {
		while (j > 0 && b[i] != b[j + 1]) j = kmp[j];
		if (b[i] == b[j + 1])j++;
		kmp[i] = j;
	}
	j = 0;
	for (int i = 1; i <= ll; i++) {
		while (j > 0 && a[i] != b[j + 1]) j = kmp[j];
		if (a[i] == b[j + 1])j++;
		if (j == rr) {
			printf("%d\n", i - rr + 1);
			j = kmp[j];
		}
	}
//	for (int i = 1; i <= rr; i++) printf("%d ", kmp[i]);
	return 0;
}

【模板】字符串哈希 - 洛谷

Hash算法可以将一个数据转换为一个标志,这个标志和源数据的每一个字节都有十分紧密的关系。Hash算法还具有一个特点,就是很难找到逆向规律。(百度百科)

这个题目模板感觉是要求尝试求出每个字符串的唯一“编号”,然后以这个唯一“编号”来判断

(随便找个质数当进制,怎么取模听电脑由命)

(用快排还能寄是我没想到的)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<malloc.h>

char all[10005][1505];
unsigned long long int num[10005]={0};

void qqsort(int op,int ed);

int main()
{
	int n,l;
	scanf("%d",&n);getchar();
	for(int i=0;i<n;i++){
		scanf("%s",all[i]);
		l=strlen(all[i]);
		for(int j=0;j<l;j++) num[i]=num[i]*13331+all[i][j];
	}
	unsigned long long int k;
	for(int i=0;i<n;i++){
		for(int j=i;j<n;j++){
			if(num[i]<num[j]){
				k=num[i];num[i]=num[j];num[j]=k;
			}
		}
	}
	int end=1;
	for(int i=1;i<n;i++){
		if(num[i]!=num[i-1]) end++;
	}
	printf("%d",end);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值