首页 > 其他分享 >通关数据结构 day_06 -- KMP

通关数据结构 day_06 -- KMP

时间:2022-10-13 17:22:12浏览次数:74  
标签:06 前缀 -- next 后缀 int KMP 字符串 长度

KMP

原理

失败了退一步,再尝试

假设我们有一个字符串

暴力枚举法

假设 S[N] 是原串,P[M] 是模式串

for(int i = 1;i <= n;i++)
{
	bool flag = true;
	for(int j = 1;j <= m;j++)
	{
		if(s[i]!=p[j])
		{
			flag = false;
			break;
		}
	}
}

在暴力做法中,若出现在匹配不合适的情况,只会将 匹配的起点往后移动一位

那么在我失败后,我新的模板串往后移动多少位可以开始匹配?

也就是我新的模板串往后移动多少位使得 我新的模板串从 起点到我上一次失败的点的串 和 原串相等

引入 next 数组

而 next[ i ] 的意义就是 ,以 i 为终点的后缀 和 从 1 开始的前缀相等,而且后缀的长度最长

假设 next[ i ] = j 那么其含义就是p[1,j] = p[i-j+1,i]

假设我们匹配出错的点是 i,对于模式串来说出错的点是 j+1,也就是 s[i] != p[j+1],那么这个时候我们需要移动我们的模式串,也就是调用我们的next数组,找到以这个点为终点的后缀 和 从 1 开始的前缀,最长的相等,也就是 next[ j ]

模板

// s[]是长文本,p[]是模式串,n是s的长度,m是p的长度
求模式串的Next数组:
for (int i = 2, j = 0; i <= m; i ++ )
{
    while (j && p[i] != p[j + 1]) j = ne[j];
    if (p[i] == p[j + 1]) j ++ ;
    ne[i] = j;
}

// 匹配
for (int i = 1, j = 0; i <= n; i ++ )
{
    while (j && s[i] != p[j + 1]) j = ne[j];
    if (s[i] == p[j + 1]) j ++ ;
    if (j == m)
    {
        j = ne[j];
        // 匹配成功后的逻辑
    }
}

举例

假设有数组

S = " abababc"

P = "abababab"

那么我们有

next[1] = 0 //我不能等于自己

next[2] = 0 //ab 的前缀是 a,后缀是 b,不相等

next[3] = 1 //aba 长度是 1 的时候 前缀是 a,后缀是 a;长度是 2 的时候 前缀是 ab ,后缀是 ba,不匹配,所以 值为 1

next[4] = 2 //abab 长度为 2 的时候 前缀是 ab,后缀是 ab,长度为 3 的时候 前缀是 aba,后缀是 bab,不匹配,所以值为 2

依次类推

next[5] = 3

next[6] = 4

next[7] = 5

next[8] = 6

当我们进行 kmp 匹配的时候,当我们下标是 7 的时候不相等了【也就是 {s[7] = c} != {p[7]=a},i = 7,j = 6】

那么我找到 j = ne[j] == ne[6] = 4

为什么?

因为这个时候 是长度为6的字符串,他的前缀和后缀相等的最大 也就是 我们 next[6]的值也就是 4

练习

831. KMP字符串 - AcWing题库

给定一个字符串 S,以及一个模式串 P,所有字符串中只包含大小写英文字母以及阿拉伯数字。

模式串 P 在字符串 S 中多次作为子串出现。

求出模式串 P 在字符串 S 中所有出现的位置的起始下标。

输入格式

第一行输入整数 N,表示字符串 P 的长度。

第二行输入字符串 P。

第三行输入整数 M,表示字符串 S 的长度。

第四行输入字符串 S。

输出格式

共一行,输出所有出现位置的起始下标(下标从 0 开始计数),整数之间用空格隔开。

数据范围

1≤N≤105
1≤M≤106

输入样例:

3
aba
5
ababa

输出样例:

0 2
#include<iostream>
using namespace std;

const int N = 1e6+10;
int ne[N];
char s[N],p[N];
int n,m;

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    cin >> n >> p + 1 >> m >> s + 1;
    
    //  求 next 过程
    for(int i = 2,j = 0;i <= n;i++)
    {
        while(j && p[i]!=p[j+1])
        {
            j = ne[j];
        }
        if(p[i]==p[j+1])
        {
            j++;
        }
        ne[i] = j;
    }

    //  kmp 匹配过程   
    for(int i = 1,j = 0;i <= m;i++)
    {
        // j 没有退回起点 并且 s[i] 不能和 p[j+1] 匹配
        while(j && s[i]!=p[j+1])
        {
            j = ne[j];
        }
        //  已经匹配
        if(s[i]==p[j+1])
        {
            j++;
        }
        if(j == n)
        {
            //匹配成功
            cout << i-n << " ";
            j = ne[j];
        }
    }
    
    return 0;
}

标签:06,前缀,--,next,后缀,int,KMP,字符串,长度
From: https://www.cnblogs.com/ShibuyaKanon/p/16788897.html

相关文章

  • vue拖拽排序功能
    实现效果(可以拖拽排序)  实现步骤一:安装依赖npminstallvuedraggable--save二:在页面中引入importdraggablefrom"vuedraggable";components:{draggab......
  • linux:安装pytorch(python3.6.8 / pytorch 1.10.1+cu102)
    一,pytorch的官网:https://pytorch.org/如图:根据自己的需求选择版本、平台、语言环境等信息,然后运行命令即可说明:刘宏缔的架构森林是一个专注架构的博客,地址:https:/......
  • 每日一结
    剑指Offer36.二叉搜索树与双向链表整体思路中序遍历;所以:mid(root.left);内容;mid(root.right);内容:初始化pre!=null则让pre.right=cur;cur.left=pre;【由......
  • 视频融合平台EasyCVR级联小众平台,需要注意什么?
    EasyCVR具备强大的视频接入、汇聚与管理、视频分发等视频能力,可实现的视频功能包括:视频监控直播、云端录像、云存储、录像检索与回看、智能告警、平台级联、服务器集群、......
  • CSS——下拉菜单
    1.下拉菜单通常使用在鼠标过程中,当鼠标悬停是出现一个下拉的菜单。2.使用任何元素打开下拉菜单内容,例如<span>或<button>元素3.使用容器元素<如div>创建下拉内容,并在......
  • gunicorn运行报错Error: Unable to configure root logger: Unable to add handler ‘
    把logconfig_dict改为LOGGING解决logconfig_dict={'version':1,'disable_existing_loggers':False,'loggers':{"gunicorn.error":{......
  • js打印输出九九乘法表
    for(leti=1;i<=9;i++){                    letstr='';                    for(letj=1;j<=i;j++)......
  • GD32固件库学习(一)-MDK Arm开发环境搭建
    1固件库下载2进入Template文件夹,打开官方提供的模板*注意:由于例程例程的keil文件都是keil4版本的,打开会识别不到芯片,即便前面安装了,将文件名由project.uvproj,.uvpr......
  • Typora使用 EasyBlogImageForTypora上传图片
      最近在使用Typora的过程中发现不可以直接粘贴图片,百度后发现需要配置个人图床,于是便用GitHub配置了一个,没想到这才是噩梦的开始,因为必须使用代理才能正常加载图片,也就......
  • js中==、===、!=、!==的使用及区别
    代码样例varnum=1;varstr='1';vartest=1;test==num//true相同类型相同值test===num//true相同类型相同值test!==num//falsetest与num类......