首页 > 编程语言 >杂算法

杂算法

时间:2023-12-08 20:22:30浏览次数:36  
标签:主串 AC 下标 后缀 next 算法 字符串

update on 2023.11.17 NOIP前来复习板子,发现KMP整理的不是很到位,所以更新详细一些。

模板题


抽象的blog

浅显易懂的讲解视频:(dalao讲得太好了\(%%%\))

备用网址


\(kmp\)(字符串匹配)的概念:

  • 主串:被匹配的字符串
  • 模式串:匹配的串
  • 最长前后缀:一个字符串某个前缀后后缀相同,而且长度尽可能长

先讲暴力算法:
遍历主串,如果有一个字符与模式串不一样,适配了,那么主串就回到原来的位置+1,相当于一个 \(O(n \times m)\) 的复杂度.

因为复杂度过大,所以三位大佬(K,M,P)发明出了KMP算法,他的核心思想就是利用已知的数据,利用好,不往回头走,从而做到 \(O(n+m)\) 的复杂度。

设:

  • 主串的下标是 \(i\)
  • 模式串的下标是 \(j\)

他的做法就是不让i往回走,所以就能达到线性的时间复杂度

首先我们要预处理出 \(next\) 数组。

预处理完后。我们需要遍历一遍主串,按照暴力的思想一个个字符串相匹配,如果失配了。

那么我们设 \(k\) 为: 上一个下标(最后一个正确匹配的下标)的 \(next\) 数组。

然后将 $ j $ 加上 \(k\) ,也就是将模式串的下标往右移动k个下标,这样就可以跳过一些字符,但依然不影响答案。如果有一部分重复的例如: \(ABABC\) 中找 \(ABC\),自然,匹配到 \(C\) 的时候,就失配了。所以就找到第二个字符的 \(next\) 数组的值,为 \(2\),所以直接跳过了前面的 \(AB\),就直接配对了 \(ABC\)。

但是为什么这个 \(next\) 数组可以知道?

因为 \(next\) 数组存储的是主串中从头到这个下标的最长前后缀。如果他们有相同的前后缀,那么就可以跳过这些(注意:最长前后缀的长度不能等于计算的字符串,不然跳过整个字符串还有什么意义?)

当然,计算每一个字符串的最长前后缀也不是暴力的,我们可以分两种情况,如果遍历到 \(i\) ,那么已知\([1,i-1]\)的最长前后缀,假设其长度为\(k\),那么这个字符串的 \([1,k]\) 和 \([i-k,i-1]\) 相等,如果 \(i\) 和 \(k+1\) 能相等,那么 \([1,i]\) 的最长前后缀长度就是 \(k+1\) 否则,我们就按照之前的字符串的前缀。(具体看视频

更新部分:

数学课上拿着NOI辞典上写的一些笔记。。

For example:

第一种情况:

每一次比较 \(S_{next_{i-1} + 1}\) 的位置和 \(S_i\) 对比,如果匹配成功,那么显然是 \(next_i = next_{i-1} + 1\)。

第二种情况:匹配失败

假设首先知道 \(next_{12} = 5\)

ACBACDDACBAC 后面加入一个 B。显然 D 不等于 B。所以此时我们就要往前跳。

我们发现:ACBACDDACBAC 中前面的 ACBAC 的后面的 AC 和后面的 ACBAC 的后面的 AC说的可能有点绕,不太好讲,具体还是看图吧。两个字符串相等,他们的后缀也一定相等。(说了跟说了似的

然而,前面的 ACBAC 的 \(next\) 数组是 \(2\)。因此其中的两个 AC 也是一样的。

ACBACDDACBAC 的前缀 AC 和后缀 AC 是一样的,于是下标往右移,发现左边的 AC + B 是与新加入的 B 相匹配。

于是就可以知道 ACBACDDACBACB 的 \(next\) 数组是 \(2+1=3\)。

因此,讲完了,感觉还是图画的清楚点。

实现流程:根据书中的话来说:

(1)设 \(j\) 为 \(next_{i-1}\) ,\(S_{j+1} = s_i\) 那么 \(next_i = j+1\)

(2)若不相等,\(j\) 需要变得更小,以满足 \(S_{[1,j]} = S_{[i-j,j-1]}\) 的最大值。即 \(j = next_j\) (其实上文主要解释了 \(j\) 为什么会等于 \(next_j\)。若此时 \(S_{j+1} = S_i\) 那么 \(next_i = j+1\)

(3)若仍然不相等,重复(2)直到 \(j=0\) 为止。
https://cdn.luogu.com.cn/upload/image_hosting/obc9fny4.png


AC Code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6+5;
char s1[N],s2[N];
int l1,l2;
int nxt[N];
int main(){
	scanf("%s",s1+1);l1 = strlen(s1+1);
	scanf("%s",s2+1);l2 = strlen(s2+1);
	for(int i = 2,j = 0;i <= l2;++i){
		while(j&&s2[i] != s2[j+1])j=nxt[j];
		if(s2[i]==s2[j+1]) ++j;
		nxt[i]=j;
	}
	for(int i = 1,j = 0;i <= l1;++i){
		while(j && s1[i] != s2[j+1])j=nxt[j];
		if(s1[i]==s2[j+1]) ++j;
		if(j==l2) printf("%d\n",i-l2+1),j=nxt[j]; 
	}
	for(int i = 1;i <= l2;i++) printf("%d ",nxt[i]);
	return 0;
}

有什么错误欢迎指出。

标签:主串,AC,下标,后缀,next,算法,字符串
From: https://www.cnblogs.com/gsczl71/p/17888951.html

相关文章

  • 数据结构与算法----------3
    队列队列也是一种受限制的线性表,只能在一端进行插入,在另一端进行删除。当然也有一种特殊的队列,名叫双端队列,也就是一段既可以插入也可以删除,在另一端也可以插入和删除。这就是双端队列。队列的顺序实现(非环形数组)代码实现//队列的顺序实现(非环形数组)#define_CRT_SECUR......
  • 二分——acwing算法基础课笔记
    个人笔记,欢迎补充、指正。此次完全以个人理解来写。整数二分 整数二分有两种,分别是找左边界和找右边界。 寻找符合要求的左边界:绿色点intbsearch_1(intl,intr){while(l<r){intmid=l+r>>1;//对应下界,最左if(check(mid))r=......
  • 数据结构与算法---------2
    栈栈是一个具有一定操作约束的线性表,只能在一端(栈顶,top)做插入和删除。栈的顺序实现//栈的顺序实现#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#include<string.h>#include<math.h>#include<time.h>#include<stdbool.h>#defineuun......
  • 矿山自救器检测的AI算法工作原理是什么?在智慧矿山应用广吗?
    智慧矿山作为当今矿业领域的热门话题,其应用已经逐渐成为行业发展的必然趋势。在智慧矿山中,矿山自救器检测的AI算法是一个重要的组成部分,通过这一技术,可以大大提高矿工的安全水平和生产效率。那么,矿山自救器检测的AI算法工作原理是什么?在智慧矿山应用广泛吗?接下来,我们将从技术原理和......
  • 【EMNLP 2023】基于知识迁移的跨语言机器阅读理解算法
    近日,阿里云人工智能平台PAI与华南理工大学朱金辉教授团队、达摩院自然语言处理团队合作在自然语言处理顶级会议EMNLP2023上发表基于机器翻译增加的跨语言机器阅读理解算法X-STA。通过利用一个注意力机制的教师来将源语言的答案转移到目标语言的答案输出空间,从而进行深度级别的辅助......
  • React diff 算法详解
    代码参照React16.13.1什么是Diff在render阶段的beginWork函数中,会将上次更新产生的Fiber节点与本次更新的JSX对象(对应ClassComponent的this.render方法返回值,或者FunctionComponent执行的返回值)进行比较。根据比较的结果生成workInProgressFiber,即本次更新的Fiber节......
  • Vue2 的 diff 算法详解
    所谓diff算法,就是通过比对新旧两个虚拟节点不一样的地方,针对那些不一样的地方进行新增或更新或删除操作。接下来详细介绍节点更新的过程。首先进行静态节点处理,判断新旧两个虚拟节点是否是静态节点,如果是,就不需要进行更新操作,可以直接跳过更新比对的过程。再更新处理新老节点......
  • Vue3 diff算法详解
    Diff更新算法由于目前Vue3对于性能的优化做了很多的处理,所以其在更新时并不会对所有的节点都进行diff更新。目前会进行diff更新的有以下两种情况:v-for容器节点自写的render()函数还有一种特殊情况会进行无diff的按序更新,这种更新是全替换模式,非常耗时:无key值的v-for语句,......
  • HydroOJ 从入门到入土(6)Caddy设置自动SSL证书, 开启高压缩比算法(brotli)节约网络带宽
    Caddy既出,何需Nginx?目录1.Caddy是啥2.Caddy配置简介3.使用gzip/br节省带宽3.1先把静态文件全部压缩3.2caddyfile中开启precompressed选项3.3查看是否成功1.Caddy是啥Caddy是用来替代Nginx的新一代反代工具,配置简单很多.有了Caddy,就不要再装N......
  • 路径规划算法 - 求解最短路径 - A*(A-Star)算法
    Dijkstra(迪杰斯特拉)算法A*(A-Star)算法是一种静态路网中求解最短路径最有效的直接搜索方法,也是解决许多搜索问题的有效算法。算法中的距离估算值与实际值越接近,最终搜索速度越快。A*算法是一个“搜索算法”,实质上是广度优先搜索算法(BFS)的优化A*算法的作用是“求解最短路径......