首页 > 其他分享 >【学习笔记】KMP字符串匹配

【学习笔记】KMP字符串匹配

时间:2022-09-22 09:35:21浏览次数:43  
标签:匹配 int 笔记 next KMP 字符串 include

字符串匹配——KMP算法

给定两个字符串s1和s2,询问s2在s1中出现的位置(定义为出现时的第一个字符在s1中的位置)

暴力枚举

看到字符串匹配(如果你还不会KMP/Hash的话),八成是要用暴力枚举的方法(可是这样极其容易被卡掉)因此三位神犇发明了KMP算法

顺便%一下dalao

D. E. Knuth 、J.H. Morris and V.R.Pratt

next数组

KMP算法的核心操作

为了方便,我们将s1定义为主串,s2定义为模式串

可以从左到右一位一位的匹配,失配了就从头再来(这是暴力枚举)

所以我们可以想更优的方法,利用已经匹配的部分,从而只移动模式串,让主串保持不变,可以用指针j表示模式串匹配到了哪一位

举个栗子

ABCABCDEFG
ABCABB

发现匹配到第六位时失配力,此时j在B也就是第六位

可以移动一下

ABCABCDEFG
   ABCABB

此时j在C的位置(第三位)力

可以看出,每次移动后,假如移动j到了k,则字符串前k-1位==j之前的k-1位

所以我们可以用next数组来记录对于每一个j的k的位置,即最长公共前后缀de长度

而对于第1位/第2位,其最长公共前后缀的长度始终为1

即next[0]=1,next[1]=1;

预处理&匹配

上文介绍了next数组以及指针j如何移动

那么怎么预处理next数组呢?

其实很简单

让模式串与自己匹配就好啦

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

然后就是主串与模式串之间的匹配

	for(int i=1;i<=len_a;i++)
	{
		while(j && b[j+1]!=a[i])
		{
			j=kmp[j];
		}
		
		if(b[j+1]==a[i])
		{
			j++;
		}
		
		if(j==len_b)
		{
			cout<<i-j+1<<endl;
			j=kmp[j];
		}
	}

完整の板子

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>

using namespace std;

const int maxn=1e6+5;

int kmp[maxn],j;

int len_a,len_b;

char a[maxn],b[maxn];

int main()
{
	cin>>a+1;
	cin>>b+1;
	
	len_a=strlen(a+1);
	len_b=strlen(b+1);
	
	for(int i=2;i<=len_b;i++)
	{
		while(j && b[j+1]!=b[i])
		{
			j=kmp[j];
		}
		
		if(b[j+1]==b[i])
		{
			j++;
		}
		
		kmp[i]=j;
	}
	
	j=0;
	
	for(int i=1;i<=len_a;i++)
	{
		while(j && b[j+1]!=a[i])
		{
			j=kmp[j];
		}
		
		if(b[j+1]==a[i])
		{
			j++;
		}
		
		if(j==len_b)
		{
			cout<<i-j+1<<endl;
			j=kmp[j];
		}
	}
	
	for(int i=1;i<=len_b;i++)
	{
		cout<<kmp[i]<<" ";
	}
	
	return 0;
}

無限はゼロに近いが、ゼロではない可能性がある

标签:匹配,int,笔记,next,KMP,字符串,include
From: https://www.cnblogs.com/SitoASK/p/16718010.html

相关文章

  • Jenkins 20220921笔记本1
                            ......
  • 【笔记】P1606 [USACO07FEB]Lilypad Pond G 及相关
    题目传送门建图首先,根据题目,可以判断出这是一道最短路计数问题。但是要跑最短路,首先要用他给的信息建图,这是非常关键的一步。根据题意,我们可以想出以下建图规则:起点......
  • MAUI学习笔记(五)-MVVM模式
    一、为什么使用MVVM模式:  MVVM模式有助于将应用程序的业务和表示逻辑与用户界面(UI)清晰分离。保持应用程序逻辑和UI之间的清晰分离有助于解决许多开发问题,并使......
  • 学习笔记273—解决linux系统挂载盘Read-only file-system问题
    问题描述笔记本电脑装的双系统,windows10+ubuntu18.04。不知道啥时候,挂载的windowsD盘和E盘无法写入,即不能创建文件和文件夹,也不能对文件进行操作,提示错误“Read-onlyfil......
  • JAVA字符串转Unicode编码
    importjava.util.ArrayList;publicclassHello{publicstaticvoidmain(String[]args){Strings="我爱JAVA";System.out.println(s2uni......
  • 广义二项级数与广义指数级数学习笔记
    广义二项级数与广义指数级数广义二项级数定义定义广义二项级数如下:\[\mathcalB_t(z)=z\mathcalB_t^t(z)+1\tag{1}\]记\(F(z)=\mathcalB_t(z)-1\),那么有\(F(z)=z(......
  • Javaweb学习笔记第十弹
    本章存在的意义,大概就是为了回顾一下被遗忘不久的html了HTML:超文本标记语言(不区分大小写,语法较为松散,但建议书写时规范一些)HTML标签由浏览器来解析标签展示图片具体详......
  • letcode算法--17.字符串相乘
    给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。注意:不能使用任何内置的BigInteger库或直接将输入转......
  • javaScript 字符串方法,字符串搜索,
     //这是字符串 能够使用单引号或双引号    varmko='helloworedw'    varqwe="hello worasd"    //new 一个字符串   ......
  • vue学习笔记(二):vue目录结构,及vue组件和用法
    一、目录结构: 二、vue组件:  项目目录中的app.vue是一个顶级组件,可以删除里面的代码,然后来重新写:  注意:<template>标签下面只能有一个根元素,也就是说下面的写......