【kmp算法】字符串匹配

这篇具有很好参考价值的文章主要介绍了【kmp算法】字符串匹配。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一,解决问题

  kmp算法解决的是字符串匹配的问题,具体来说假定我们要在主串s[ ] 中匹配模式串p[ ],找到匹配到的位置loc;

二,具体实现和演变过程

  最自然的想法是暴力写法 (BF)枚举主串字符s[ i ] ,和模式串p[ j ]。一个一个匹配,如果匹配失败,i指针回退回起点,往前进一位,再次进行比较,知道匹配成功。

代码如下:

#include<bits/stdc++.h>
#define int long long
const int INF = 1e18 + 10,maxn = 1e5 + 10;
using namespace std;

char p[maxn],s[maxn];
int n,m;
signed main (){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    
    cin>>m>>(p + 1)>>n>>(s + 1);
    for(int i = 1; i <= n; i++){
        int j = 1;
        while(s[i] == p[j] && j <= m){
            i++;
            j++;
        }
        if(j == m + 1) {
            cout<< i - j + 1 << '\n';
        }
        i = i - j + 1;//回退
    }
    
    return 0;
}

  时间复杂度是O(nm) 因为对于s[i],最多被比较m次,每次比较都会++指针,共有n个字符会被比较。

  kmp算法就是通过一些方法减少了比较次数,减少了时间复杂度的做法。

具体来说,我们先想办法使得i指针不回退,首先,我们已经知道匹配失败的位置前面所有位置都是匹配成功的,假设匹配失败的前一个位置为j 那么匹配失败的位置为j + 1,因为j + 1匹配失败,那么我们需要向右滑动字符串p,此时假设有一个ne【】数组,记录了p[i] 使得 p[1,ne[j]] = p[j-ne[j]+1,j] 的值即最长相等真字串长度,那么由于p[1,j] 之前是匹配成功的,那么只需要将j 回退到p[1,ne[j]] = p[j-ne[j]+1,j] 即可,任然只需要比较p[j + 1] = s[i]。代码如下:

 

    for(int i = 1,j = 0; i <= m; i++){
        while(j && p[j + 1] != s[i]) j = ne[j];
        if(p[j + 1] == s[i]) j++;
        if(j == n){
            cout<<i - n<<' ';
            j = ne[j];
        }
    }

  那么问题来了,如何确定ne【】数组,我们采取相同的策略,假定现在匹配前缀p[1,j] 和后缀 p[i- j + 1,i]如果匹配成功,只需将长度j++,(还记得ne【】数组的定义吗)如果匹配失败,只需要前后缀各自减少长度ne[j] 同理,现在匹配失败的位置是p[j + 1],那么只需回退j指针就能找到前一个p[1,j - ne[j]] 和 p[i-ne[j]+1,i] (更新位置i时。i前面的ne数组已经确定)那么代码如下(j 表示的意义不仅是匹配位置,也有长度的意思,以为前缀表示为p[1,j]):

    //ne数组的生成过程中,考察ne[i]和ne[i-1] i >= 2;
    //完成ne[i-1]匹配后可以确定p[1,j] = p[i-j,i-1]
    //那么如果p[i] != p[j+1]
    //应该回退j舍弃部分p[1,j] 的后缀和 p[i-j,i-1] 的前缀
    //回退到j = ne[j] (i-1前的ne数组都已完成维护)
    //此时p[1,ne[j]] 是p[1,j] 的真子集并且p[1,ne[j]] = p[j-ne[j]+1,j]
    //匹配过程
    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;
    }
    

  那么完整的代码如下:

#include<bits/stdc++.h>
#define int long long
const int INF = 1e18 + 10,maxn = 1e6 + 10;
using namespace std;

char p[maxn],s[maxn];
int ne[maxn];
signed main (){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    
    int n,m;
    cin>>n>>(p+1)>>m>>(s+1);
    //ne数组的生成过程中,考察ne[i]和ne[i-1] i >= 2;
    //完成ne[i-1]匹配后可以确定p[1,j] = p[i-j,i-1]
    //那么如果p[i] != p[j+1]
    //应该回退j舍弃部分p[1,j] 的后缀和 p[i-j,i-1] 的前缀
    //回退到j = ne[j] (i-1前的ne数组都已完成维护)
    //此时p[1,ne[j]] 是p[1,j] 的真子集并且p[1,ne[j]] = p[j-ne[j]+1,j]
    //匹配过程
    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;
    }
    
    for(int i = 1,j = 0; i <= m; i++){
        while(j && p[j + 1] != s[i]) j = ne[j];
        if(p[j + 1] == s[i]) j++;
        if(j == n){
            cout<<i - n<<' ';
            j = ne[j];
        }
    }
    return 0;
}

 文章来源地址https://www.toymoban.com/news/detail-760617.html

到了这里,关于【kmp算法】字符串匹配的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C#,字符串匹配(模式搜索)KMP算法的源代码与数据可视化

      D.E.Knuth   J.H.Morris KMP 算法(Knuth-Morris-Pratt 算法)是其中一个著名的、传统的字符串匹配算法,效率比较高。 KMP算法由 D.E.Knuth , J.H.Morris 和 V.R.Pratt 在 Brute-Force 算法的基础上提出的模式匹配的改进算法。因此人们称它为“克努特—莫里斯—普拉特算法”,简称KMP算法。K

    2024年01月25日
    浏览(29)
  • P3375 【模板】KMP 字符串匹配

    给出两个字符串 s 1 s_1 s 1 ​ 和 s 2 s_2 s 2 ​ ,若 s 1 s_1 s 1 ​ 的区间 [ l , r ] [l, r] [ l , r ] 子串与 s 2 s_2 s 2 ​ 完全相同,则称 s 2 s_2 s 2 ​ 在 s 1 s_1 s 1 ​ 中出现了,其出现位置为 l l l 。 现在请你求出 s 2 s_2 s 2 ​ 在 s 1 s_1 s 1 ​ 中所有出现的位置。 定义一个字符串 s s s 的

    2024年02月14日
    浏览(29)
  • PTA 7-1 字符串模式匹配(KMP)

    给定一个字符串 text 和一个模式串 pattern,求 pattern 在text 中的出现次数。text 和 pattern 中的字符均为英语大写字母或小写字母。text中不同位置出现的pattern 可重叠。 输入格式: 输入共两行,分别是字符串text 和模式串pattern。 输出格式: 输出一个整数,表示 pattern 在 text 中的出

    2024年02月06日
    浏览(22)
  • 【leetcode 力扣刷题】字符串匹配之经典的KMP!!!

    以下是能用KMP求解的算法题,KMP是用于字符串匹配的经典算法【至今没学懂………啊啊啊】 题目链接:28. 找出字符串中第一个匹配项的下标 题目内容: 题意还是很好理解的,要在字符串haystack中查找一个完整的needle,即字符串匹配。 暴力求解就是用 两层循环 :haystack从第

    2024年02月09日
    浏览(23)
  • Leetcode的AC指南 —— 字符串/KMP:28.找出字符串中第一个匹配项的下标

    摘要: Leetcode的AC指南 —— 字符串/KMP:28.找出字符串中第一个匹配项的下标 。题目介绍:给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。 题目介绍 :给你两

    2024年02月02日
    浏览(37)
  • 数据结构课设:基于字符串模式匹配算法的病毒感染检测问题

    1.掌握字符串的顺序存储表示方法。 2.掌握字符串模式匹配算法BF算法或KMP算法的实现。 问题描述 医学研究者最近发现了某些新病毒,通过对这些病毒的分析,得知它们的DNA序列都是环状的。现在研究者已收集了大量的病毒DNA和人的DNA数据,想快速检测出这些人是否感染了

    2023年04月27日
    浏览(28)
  • 数据结构--字符串的KMP算法

    朴素模式匹配算法: 一旦发现当前这个子串中某个字符不匹配,就只能转而匹配下一个子串(从头开始) 但我们可以知道: 不匹配的字符之前,一定是和模式串一致的 color{red}不匹配的字符之前,一定是和模式串一致的 不匹配的字符之前,一定是和模式串一致的 我们可以利用

    2024年02月12日
    浏览(35)
  • LeetCode:459. 重复的子字符串 —【2、KMP算法】

    🍎道阻且长,行则将至。🍓 🌻算法,不如说它是一种思考方式🍀 算法专栏: 👉🏻123 题目描述 :给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。 来源:力扣(LeetCode) 难度: 简单 提示: 1 = s.length = 104 s 由小写英文字母组成 示例 1: 输入:

    2024年02月04日
    浏览(32)
  • 代码随想录 Leetcode459. 重复的子字符串(KMP算法)

            此解法读者需要了解什么是KMP算法以及KMP算法中next数组的具体含义才能理解         因为在KMP算法的next数组中,next[index]表示 i ndex之前的最大长度的相同前缀后缀值 ,那么要判断整个字符串中是否由重复字串构成,只需要以下两个条件:         1.next[n - 1] !=

    2024年01月19日
    浏览(43)
  • 【字符串匹配】暴力匹配算法

    ​ 暴力匹配算法,也称为朴素字符串匹配算法,是一种简单但不高效的字符串匹配方法。它的原理非常直观,其主要思想是逐个字符地比较文本串和模式串,从文本串的每个可能的起始位置开始,依次检查是否有匹配的子串。以下是暴力匹配算法的详细原理: 1. 一个字一个

    2024年02月09日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包