详解KMP算法(字符串匹配算法)(高效寻找子串)(一个一个匹配,推己及人,根据己和别串匹配的值,确定他串下一次应该匹配的位置,根据己串求出text[ ],就是下一次应该母串确定的位置)

【数据结构】 字符串模式匹配 模式匹配目前有两种方法: BF算法和KMP算法 BF算法 思路: 从目标串的第一个字符和模式串的第一个字符开始,依次比较每个字符,如果相同指针同步后移比较后续字符,如果不同i指针后移一个,j指针回到第一个字符重新匹配,若匹配成功就返回模式串t中第一个字符在目标串中的位置,失败返回0 代码: int index(Sqstring s,Sqstring t){ int i=j=1; //下标从1开始 while(i<=s.length&&j<=t... 阅读详情

https://www.cnblogs.com/ZuoAndFutureGirl/p/9028287.html

3.3.1 寻找最长前缀后缀

    如果给定的模式串是:“ABCDABD”,从左至右遍历整个模式串,其各个子串的前缀后缀分别如下表格所示:

    也就是说,原模式串子串对应的各个前缀后缀的公共元素的最大长度表为(下简称《最大长度表》):

 

3.3.2 基于《最大长度表》匹配

    因为模式串中首尾可能会有重复的字符,故可得出下述结论:

失配时,模式串向右移动的位数为:已匹配字符数 - 失配字符的上一位字符所对应的最大长度值

    下面,咱们就结合之前的《最大长度表》和上述结论,进行字符串的匹配。如果给定文本串“BBC ABCDAB ABCDABCDABDE”,和模式串“ABCDABD”,现在要拿模式串去跟文本串匹配,如下图所示:

        

  • 1. 因为模式串中的字符A跟文本串中的字符B、B、C、空格一开始就不匹配,所以不必考虑结论,直接将模式串不断的右移一位即可,直到模式串中的字符A跟文本串的第5个字符A匹配成功:

  • 2. 继续往后匹配,当模式串最后一个字符D跟文本串匹配时失配,显而易见,模式串需要向右移动。但向右移动多少位呢?因为此时已经匹配的字符数为6个(ABCDAB),然后根据《最大长度表》可得失配字符D的上一位字符B对应的长度值为2,所以根据之前的结论,可知需要向右移动6 - 2 = 4 位。

  • 3. 模式串向右移动4位后,发现C处再度失配,因为此时已经匹配了2个字符(AB),且上一位字符B对应的最大长度值为0,所以向右移动:2 - 0 =2 位。

           

  • 4. A与空格失配,向右移动1 位。

  • 5. 继续比较,发现D与C 失配,故向右移动的位数为:已匹配的字符数6减去上一位字符B对应的最大长度2,即向右移动6 - 2 = 4 位。

           

  • 6. 经历第5步后,发现匹配成功,过程结束。

          

    通过上述匹配过程可以看出,问题的关键就是寻找模式串中最大长度的相同前缀和后缀,找到了模式串中每个字符之前的前缀和后缀公共部分的最大长度后,便可基于此匹配。而这个最大长度便正是next 数组要表达的含义。

3.3.3 根据《最大长度表》求next 数组

    由上文,我们已经知道,字符串“ABCDABD”各个前缀后缀的最大公共元素长度分别为:

 

 

    而且,根据这个表可以得出下述结论

 

  • 失配时,模式串向右移动的位数为:已匹配字符数 - 失配字符的上一位字符所对应的最大长度值

    上文利用这个表和结论进行匹配时,我们发现,当匹配到一个字符失配时,其实没必要考虑当前失配的字符,更何况我们每次失配时,都是看的失配字符的上一位字符对应的最大长度值。如此,便引出了next 数组。

    给定字符串“ABCDABD”,可求得它的next 数组如下:

 

   把next 数组跟之前求得的最大长度表对比后,不难发现,next 数组相当于“最大长度值” 整体向右移动一位,然后初始值赋为-1。意识到了这一点,你会惊呼原来next 数组的求解竟然如此简单:就是找最大对称长度的前缀后缀,然后整体右移一位,初值赋为-1(当然,你也可以直接计算某个字符对应的next值,就是看这个字符之前的字符串中有多大长度的相同前缀后缀)。

    换言之,对于给定的模式串:ABCDABD,它的最大长度表及next 数组分别如下:

    根据最大长度表求出了next 数组后,从而有

 

失配时,模式串向右移动的位数为:失配字符所在位置 - 失配字符对应的next 值

    而后,你会发现,无论是基于《最大长度表》的匹配,还是基于next 数组的匹配,两者得出来的向右移动的位数是一样的。为什么呢?因为:

  • 根据《最大长度表》,失配时,模式串向右移动的位数 = 已经匹配的字符数 - 失配字符的上一位字符的最大长度值

  • 而根据《next 数组》,失配时,模式串向右移动的位数 = 失配字符的位置 - 失配字符对应的next 值

    • 其中,从0开始计数时,失配字符的位置 = 已经匹配的字符数(失配字符不计数),而失配字符对应的next 值 = 失配字符的上一位字符的最大长度值,两相比较,结果必然完全一致。

    所以,你可以把《最大长度表》看做是next 数组的雏形,甚至就把它当做next 数组也是可以的,区别不过是怎么用的问题。

 

void getnext()
{
    int j=-1;
    next[0]=-1;
    for(int i=1;i<lena;i++)//next数组代表前缀和后缀相等的长度是多少,当数组匹配错误时,可以进行返回操作
    {
        
        while(j != -1 && s[i]!=s[j+1] )
        {
            j=next[j];//返回数组,每次当出现不匹配时,就返回之前匹配的数值里面
        }
        if(s[i] == s[j+1])
        {
            j++;
        }
        next[i]=j;
    }
}

 

int kmp(char *text, char *pattern)
{
    int ans=0;
    int n=strlen(text),m=strlen(pattern);
    getnext(pattern);
    int j=-1;
    for(int i=0; i<n; i++)
    {

        while( j != -1 && text[i]!=pattern[j+1] )
        {
            j=next[j];
        }
        if(text[i] == pattern[j+1])
            j++;

        if(j==m-1)
        {
            //cout<<true<<endl;
            ans++;
            
            j=next[j];//后退一步,i++,接着匹配,当做为最后一个匹配失败,继续向后匹配
        }
    }

    return ans;
}

 

next[i]是子串s[0......i]的最长相等前后缀的前缀的最后一位的下标

//next数组代表前缀和后缀相等的长度是多少,当数组匹配错误时,可以进行返回操作,当 j + 1 失配后,j应该回退到的位置!

例如:

i 0  1  2  3

  a  b  a  b

          a  b  a  b

j    -1  0  1  2  3    我们得知,前后ab相等,当匹配到 i=4 时,出现不匹配时,i=next[i]也就是说返回到s[1]这个位置来继续匹配算法

#include <stdio.h>
#include <string.h>
#include<iostream>
#include <algorithm>
using std::min;
using namespace std;
//int lena, lenb;
char *a, *b;

int next[1010];
void read()
{
    //scanf("%s", a );
    a="ababaab";
    b="aaaaaababaab";
    //lena = strlen(a);
    //lenb = strlen(b);
}

void getnext(char *s)
{
    int lena = strlen(s);
    int j=-1;
    next[0]=-1;
    for(int i=1;i<lena;i++)//next数组代表前缀和后缀相等的长度是多少,当数组匹配错误时,可以进行返回操作
    {

        while(j != -1 && s[i]!=s[j+1] )
        {
            j=next[j];//返回数组,每次当出现不匹配时,就返回之前匹配的数值里面
        }
        if(s[i] == s[j+1])
        {
            j++;
        }
        next[i]=j;
    }
}
bool kmp(char *text, char *pattern)
{
    int n=strlen(text),m=strlen(pattern);
    getnext(pattern);
    int j=-1;
    for(int i=0;i<n;i++)
    {

        while( j != -1 && text[i]!=pattern[j+1] )
        {
            j=next[j];
        }
        if(text[i] == pattern[j+1])
            j++;

        if(j==m-1)
        {
            cout<<true<<endl;
            return true;
        }
    }

    return false;
}

int main()
{
    read();
    //getnext(a);
    kmp(b,a);
    return 0;
}

next的再优化!!!1

void getnext(char *s)
{
    int lena = strlen(s);
    int j=-1;
    next[0]=-1;
    for(int i=1; i<lena; i++) //next数组代表前缀和后缀相等的长度是多少,当数组匹配错误时,可以进行返回操作
    {

        while(j != -1 && s[i]!=s[j+1] )
        {
            j=next[j];//返回数组,每次当出现不匹配时,就返回之前匹配的数值里面
        }
        if(s[i] == s[j+1])
        {
            j++;
        }

        if( j==-1 || s[i+1] != s[j+1] )//j==-1不能再回退
            next[i]=j;
        else
            next[i]=next[j];//再回退
    }
}

此时nextval[i]含义为当i+1匹配失位后,i应当回退到的最佳位置

 

i 0  1  2  3  4

  a  b  a  b  a  b

          a  b  a  b  a  b

j    -1  0  1  2  3   4

 

if( j==-1 || s[i+1] != s[j+1] )  //j==-1不能再回退
            next[i]=j;
        else
            next[i]=next[j];//再回退

假设abab与母串已经匹配失败,到了b时不成功了!

通常回退到i=0,值为a处,但是结果也是GG!

因为结果与b匹配失败也会与后面拉上来的b匹配失败!只有不相同时回退才有效!

ababab这里我们看见next[-1,-1,-1,-1,-1,3]

 

 

字符串——求解next数组 串的next数组(求next数组思路与实例) 阅读详情

相关推荐

AD元件库构建及维护之——DbLib公共元件库的使用教程

AD元件库构建及维护之——DbLib元件库的使用教程

qq_43105486的博客 2万+

基于STM32F407VET6的智能巡检小车灰度循迹系统优化设计

本文详细介绍了基于STM32F407VET6主控芯片的智能巡检小车灰度循迹系统优化设计。通过将传感器输出从数字量升级为模拟量以获取更丰富的路面信息,并采用PD控制算法结合速度管理策略,有效提升了小车在复杂弯道上的循迹稳定性与适应性。文章分享了硬件电路抗干扰设计、软件滤波及实战调优经验,为嵌入式开发者提供了从“能跑”到“跑得稳”的系统性解决方案。

weixin_28273593的博客 442

字符串匹配:字符串中查找某子串

基于C语言的字符串匹配算法,既有常规方法,又有KMP算法。

4918

《Kubernetes部署篇:基于x86_64+aarch64架构CPU+containerd一键离线部署容器版K8S1.33.3高可用集群》

《Kubernetes部署篇:基于x86_64+aarch64架构CPU+containerd一键离线部署容器版K8S1.33.3高可用集群》

东城绝神 1367

Zephyr RTOS -- 学习笔记总述

文章目录摘要1. 开发基础部分2. 内核服务入门 本笔记基于 Zephyr 版本 2.6.0-rc2 摘要 1. 开发基础部分 2. 内核服务入门 2.1 线程简介 2.2 线程 2.3 工作队列线程 2.4 调度 2.5 中断 2.6 轮询 API 2.7 信号量

思想给了我们太多的自由,而我们拖累了思想...... 4824

串的模式匹配算法(KMP算法)

说明:设主串为S,模式串为T,i表示主串元素的下标,j表示模式元素的下标,k是next( )函数找出来模式的下标 为了实现这些算法,都需要对串进行“定长顺序存储表示” 一、子串位置的定位函数(回溯法) ** 1. 算法思想: 主串的第pos个位置,和模式的第1个位置开始比较,如果相等,则继续比较后续字符;若不等,则 i 指针跑到pos的下一个位置上,j 指针继续从第1个位置开始比较……直到找到对应的子串。 代码如下: int Index(SString S, SString T, int pos) {

David_Haur的博客 1032

docker配置国内镜像源

【代码】docker配置国内镜像源。

愿听风成曲 9612

【C语言】字符串算法练习:从父串中统计子串出现的次数

快速学会在C语言中最基本的字符串查找算法!

qq_47009853的博客 1633

基于deepseek本地模型的本地知识库构建

通过以上步骤,你已经成功构建了一个基于 AnythingLLM 和 LM Studio 的本地知识库。这个系统不仅能够高效地存储和检索知识,还能结合强大的语言模型生成准确的回答。你可以根据自己的需求进一步扩展和优化这个系统,比如增加更多的文档格式支持、优化检索算法等。

qq_30178745的博客 1381

在 ABAP 平台配置 OAuth 2.0 Client(OA2C_CONFIG):一份可落地的全景实践

本文详细介绍了在ABAP平台中配置OAuth 2.0客户端的完整流程。重点讲解了四种授权类型(Client Credentials、Authorization Code、SAML 2.0 Bearer Assertion、Resource Owner Password Credentials)的适用场景和配置要点,以及客户端认证的三种方式(Client Secret、Client Certificate、mTLS)。文章提供了操作步骤、排错建议和工程实践指导,包括端点配置、回调地址管理、scopes设置等关

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 354

【我的第一篇博客】KMP算法(超详细)

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)

qq_65359222的博客 904

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

字符串匹配算法之Sunday算法

  字符串匹配查找算法中,最着名的两个是KMP算法(Knuth-Morris-Pratt)和BM算法(Boyer-Moore)。两个算法在最坏情况下均具有线性的查找时间。但是在实用上,KMP算法并不比最简单的C库函数strstr()快多少,而BM算法则往往比KMP算法快上3-5倍(未亲身实践)。但是BM算法还不是最快的算法,这里介绍一种比BM算法更快一些的查找算法Sunday算法。 ...

121

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

AC日记——【模板】KMP字符串匹配 洛谷 3375

题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置。 为了减少骗分的情况,接下来还要输出子串的前缀数组next。如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了。 输入输出格式 输入格式: 第一行为一个字符串,即为s1(仅包含大写字母) 第二行为一个字符串,即为s2(仅包含大写字母) 输出格式: ...

weixin_34026276的博客 196

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

字符串匹配-KMP算法

题目要求:给你两个字符串T,P。查找T串中是否存在P串。一般思路:从T的第一个元素开始遍历,不断匹配P中的元素,如果当前位置元素匹配失败了,就重新从P的第一个元素开始匹配。#include &lt;stdio.h&gt; #include&lt;string.h&gt; char P[105],T[105]; int main() { scanf("%s%s",T,P); int ...

哇-WA 的博客 828

数据结构 快速求next数组

快速求next数组 KMP算法中有一个求next数组的步骤。看书一直看不明白,翻阅了一些资料,说一下自己对求next数组的一些理解 首先公式是这样的: next[j] = 0 当j=1时 next[j] = 1 当j之前的字符串首尾没有匹配的字符时 next[j] = 首尾的匹配数 + 1 当j之前的字符串有首尾匹配的时候 举例: 对数组:abaabc

m0_56699208的博客 2850

KMP算法(快速模式匹配算法)c语言

欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。 新的改变 我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客: 全新的界面设计 ,将会带来全新的写作体...

lightning_c的博客 1831

串:KMP算法

//KMP算法(包括改进KMP算法) #define MAXLEN 25 #include<stdio.h> #include<string.h> typedef struct{ char ch[MAXLEN];//ch[0]不用,从ch[1]开始存,位序与下标相等,能存24个数据元素 int length; }SString; void get_next(SString T,int next[]){//求next数组 int i=1,j=0;//next[i]=...

LOG_IN_ME的博客 1078

字符串匹配:求给定字符串的next数组以及KMP算法

一. 理解字符串的next数组值 next数组值的概念涉及到字符串匹配的问题,比较抽象,先介绍一些预备知识: 1. 主串和模式串 例如我们想知道一个字符串是否包含另一个字符串时,如串S="bbc abcdab abcdabcdabde"中是否包含串s="abcdab",那么S称为主串,s称为模式串。解决这个字符串匹配问题的算法就是KMP算法。KMP算法与next数组关系密切。有...

qikaihuting的博客 9569

8086汇编实现KMP算法(中南大学智能计组实验)

  中南大学智能科学与技术专业计组实验题目:实现 KMP 算法,输入两个字符串(可以直接保存在内存中),实现快速匹配,用8086汇编实现   这个题目是所有实验题中最难搞得一个,这里附上代码,学弟学妹们需要的自取 DATA SEGMENT TARGET DB "created by ian in 2021/7/8" ;define the target TARGET_LEN DW 26 ;length of

CY2333333的博客 1210

KMP算法学习-失配表

kmp算法 失配表 理解

osnot的专栏 930

字符串匹配算法2:KMP算法

字符串匹配算法2:KMP算法1. 背景:2. KMP算法思想2.1 KMP思想2.2 匹配位置处理2.3 例子3. 失配函数3.1 什么是失配函数?3.2 next函数3.3 例子3.4 (模式串P)失配函数代码4. KMP算法实现代码例子 1. 背景: 根据暴力方法的缺点,而引出KMP算法的思想。 在暴力匹配方法中,上一次匹配失败,则下一次匹配开始时,主串指针会回溯到i+1,模式串指针会回退到......

哈尼的博客 3068

KMP算法

引入 学习一个算法要先知道它是什么,KMP算法是一种改进的字符串匹配算法。那么之前我用什么做字符串匹配呢?暴力破解,一直DF。 假设主串是ababababca,模式串是abababca。 DF算法(暴力匹配) 让模式串和主串从第一个开始匹配,如果相同,就接着比较后面的,如果不同模式串下标回到0,主串下标回到第一个匹配的位置的下一个接着比较。 算法复杂度最后为 O(m*n) KMP算法 KMP...

nntcdhl的博客 1505

KMP模式匹配 三(串)

原文请访问我的博客:xiaoshig.sinaapp.com KMP模式匹配 三(串) Time Limit:1000MS     Memory Limit:131072KB     64bit IO Format:%lld & %llu Submit Status Description 输入一个主串和一个子串,若匹配成功,则找出匹配的趟数和在子串在

码海坐标 1605
上一篇: ACM在线模版-f-zyj
下一篇: LCS(最长公共子序列)
while_black
博客等级 码龄9年 25粉丝 57原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值