首页 > 其他分享 >KMP

KMP

时间:2023-02-04 17:45:07浏览次数:52  
标签:匹配 s2 s1 jump KMP 失配 size

一、问题

​ 给出两个字符串 \(s_1\) 和 \(s_2\),若 \(s_1\) 的区间 \([l, r]\) 子串与 \(s_2\) 完全相同,则称 \(s_2\) 在 \(s_1\) 中出现了,其出现位置为 \(l\)。

现在请你求出 \(s_2\) 在 \(s_1\) 中所有出现的位置。

in:luogu P3375 【模板】KMP字符串匹配

二、常规方法

​ 对于平常的字符串匹配,我们一般会这样:

  • 如果\(s1[i] = s2[j]\rightarrow i = i + 1,j = j + 1\)

  • 否则\(i = i - j + 2, j = 1\)

    即最平常的暴力算法

​ 然而这种算法最坏是\(O(n\times m)\)的,无法接受

三、优化(即KMP)

我们可以先举个对上面方法非常不友好的栗子

​ \(s_1 = {AAAAAAB}\)

​ \(s_2 = AAAB\)

每次\(s_2\)都要遍历到\(B\)才能发现不能匹配,显然很耗时间

从上面我们可以看出,因为\(B\)和\(A\)仅仅这一个不能匹配,便浪费了前面的\(3\)次匹配

那如何把前面的\(3\)次匹配利用起来呢?

我们可以发现,前面的\(AAA\)是匹配好的,为以示区分,记为\(A_1A_2A_3\)

\[A_1A_2A_3\ ?\\\Downarrow\\ \ \ \ \ \ \ \ \ \ \ A_1A_2A_3 \]

如果能够只用判断没有判断过的 \(?\) 是否为\(A\),那就会让复杂度减小很多

即我们在匹配失败(后记为失配)后如何移动下面的字符串的指针,这尤为重要

假使我们知道了这些数值,我们便可以在每一次失配的时候将指针向前跳。

那我们如何求这个指针跳跃的数组\(jump\)呢(简称失配数组)

其实\(jump_i\)就是去求在\(~1\to i~\)中最长的前缀等于后缀的长度

下面给一组例子:

下标 1 2 3 4 5 6 7
模式串 A B A B A B C
失配数组 0 0 1 2 3 4 0
前后缀 A AB ABA ABAB

至于求法不太说得清楚,可以看一下下面的代码(抱歉)

#include<iostream>
#include<string>
using namespace std;
const int NN = 1e6 + 8;
string s1,s2;
int jump[NN];
int main(){
	cin>>s1>>s2;
	s1 = ' ' + s1;s2 = ' ' + s2;
	if(s1.size() < s2.size())swap(s1,s2);
	for(int i = 2, j = 0; i < s2.size(); ++i){
		while(j > 0 && s2[i] != s2[j+1]) j = jump[j];//如果说不能匹配就跳回之前能匹配的位置
		if(s2[i] == s2[j+1]) ++j;//否则j指针随i指针的右移而右移
		jump[i] = j; 
	}//求失配数组
	for(int i = 1,j = 0; i < s1.size(); ++i){
		while(j > 0 && (j == s2.size() || s1[i] != s2[j+1])) j = jump[j];//失配就调回该进行匹配的地方
		if(s1[i] == s2[j+1]) ++j;
		if(j == s2.size()-1) printf("%d\n",i-s2.size()+2);
	}//
	for(int i = 1; i < s2.size(); ++i){
		printf("%d ",jump[i]);
	}
}

标签:匹配,s2,s1,jump,KMP,失配,size
From: https://www.cnblogs.com/rickylin/p/17092035.html

相关文章

  • exkmp
    字符串算法参考:BilibiliT为文本串(被匹配),P为模式串(进行匹配的串)真前缀:前缀但不包含整个字符串真后缀同理kmp算法KMP算法考虑T的每个前缀的每个后缀和P的前......
  • KMP模板
    KMP算法的重点就是next数组的处理具体理解课参考这篇博客:​​点击这里​​模板:普通版本:voidGetNext(char*p,intnext[]){intpLen=strlen(p);next[0]=-1;intk=-1;......
  • KMP
    KMP总结KMP:这三位学者发明的:Knuth,Morris和Pratt,所以取了三位学者名字的首字母。所以叫做KMP。用途:字符串的匹配。KMP算法的主要核心思想就是:记录已经匹配的信息,当出现......
  • KMP
    #include<iostream>#include<string.h>#include<stdio.h>#include<fstream>usingnamespacestd;intnext[10];voidNext(char*T,intn){inti=1,j=0;nex......
  • KMP算法
    1-从oneNote上搬来2-代码String数据结构//串的堆分配存储结构(malloc占用的是堆空间)structHString{char*ch;//若是非空串,则按串长分配存储区;否则ch为NULL......
  • 扩展kmp
    扩展kmp是用来解决字符串b与字符串a的各个后缀的最长公共前缀的问题。题目参考:洛谷P5410算法思路:设\(nxt[i]\)为b以第i个字符为头的后缀,\(nxtb[i]\)为a以第i个字符为头......
  • KMP字符串匹配问题
    KMP算法本文参考资料:https://www.zhihu.com/question/21923021KMP算法是一种字符串匹配算法,可以在\(O(n+m)\)的时间复杂度内实现两个字符串的匹配。字符串匹配问题首......
  • hdu:Simpsons’ Hidden Talents(kmp)
    ProblemDescriptionHomer:Marge,Ijustfiguredoutawaytodiscoversomeofthetalentsweweren’tawarewehad.Marge:Yeah,whatisit?Homer:Takemefor......
  • hdu:剪花布条(kmp)
    ProblemDescription一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案。对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?Input......
  • 把KMP算法嚼碎了才利于消化!(C++)
    相信不少人在学数据结构的时候都被KMP算法搞的迷迷糊糊的,原理看的似懂非懂,代码写不出来,或者写出来了也不知道为什么就可以这么写。本文力求尽可能通俗详细的讲解KMP算法,让......