KMP 字符串匹配算法

简介: ✅<1>主页:C语言的前男友📃<2>知识讲解:KMP算法🔥<3>创作者:C语言的前男友☂️<4>开发环境:Visual Studio 2022🏡<5>系统环境:Windows 10💬<6>前言:KMP 算法是一个非常牛逼的字符串匹配算法

一.KMP算法介绍

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


二.为什么存在 next 数组

普通的 BF 算法,存在大量的多余匹配,为了减少模式串与主串的匹配次数以达到快速匹配的目的。来优化 BF 算法里面匹配失败后,将子串从头开始与模式匹配的问题。在实际的匹配当中,当模式串与子串匹配失败的时候,有很多的情况子串是不需要从头开始跟模式串匹配的。只需要退回到一个特定的位置。next数组就是一个长度跟子串的长度一样,数组中存储子串中每个字符在匹配失败后,需要退回的位置的数组。


当有了 next 数组,当子串与模式串匹配失败后,子串无需从最开始的位置与模式串匹配,只需从 next 数组中存储的位置开始再次与模式串匹配。


三.子串退回位置的求解


e206d2d13ca84856adb53934cb67a757.png


其中我们将在子串第一个字符匹配失败退回位置记作 -1,在第二个字符匹配失败退回记作 0 。


这样根据上述方法就能求解出,子串每个位置匹配失败后的退回位置,将每个字符匹配失败后的退回位置放在一个长度与子串长度相等数组中,这个数组就是 next 数组。


9b4ebc0a342041dfb85628c93593475a.png


四.next数组的代码求解:

第一种情况:

在求 next 数组的时候,当前位置 i 匹配失败后,k 代表退回的位置,如果 k 所在的位置的字符,与 i 所在位置的字符相等时,则 i+1 位置匹配失败后,退回的位置就是,k+1;


c692605e5c16444fb3dd09e56255ba95.png


第二种情况:

当前位置 i 匹配失败后,k 代表退回的位置,如果 k 所在的位置的字符,与 i 所在位置的字符不相等时,此时,就需要 k 继续按照当前位置的继续回退,直到回退到,k 位置的字符与 i 位置的字符相等,或者 k==-1.这个时候就回到了,第一种情况。


4d16a776496c441794f6528691f8a6b7.png


五.代码实现及讲解:

代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
void GetNext(char* sub,int *next)
{
  int sublen = strlen(sub);
  int i = 2; // i 从数组子串第三个元素开始
  int k = 0; // 代表回退的位置,k的位置始终位于,i - 1 匹配失败的回退位置的对应的 k,
             // 即可由 i - 1 位置求出 的 k,求出 i 位置的 k。
  next[0] = -1;
  next[1] = 0;
  while (i<sublen)
  {
    //当 k 回退到头的时候 即 k==-1,就需要回退到 0 号下标位置,
    //或者 如果 退回位置字符和匹配失败的字符相同
    if (k == -1 || sub[i - 1] == sub[k])
    {
      next[i] = k + 1;
      //已经求出 i 的退回位置,i 继续往后走
      i++;
      // k 要变成新的 i-1 位置的退回位置。
      k++;
    }
    //如果 退回位置字符和匹配失败的字符不相同
    else
    {
      // k 在当前位置继续回退
      k = next[k];
    }
  }
}
int KMP(char* str, char* sub, int pos)
{
  assert(str && sub);
  int StrLen = strlen(str);
  int SubLen = strlen(sub);
  assert(pos >= 0&&pos<StrLen);
  //创建 next 数组
    int * next = (int*)malloc(sizeof(int)*SubLen);
  int i = pos; //主串
  int j = 0;   //子串
  //构建next数组
  GetNext(sub,next);
  //主串和子串匹配
  while (i < StrLen && j < SubLen)
  {
    //如果匹配的字符相同就继续往后匹配
    if (j==-1 || str[i] == sub[j])
    {
      i++;
      j++;
    }
    //回退
    else
    {
      j = next[j];
    }
  }
  //当 j 遍历到最后时,也就是 子串全部匹配成功
  if (j >= SubLen)
  {
    return i - j;
  }
  //模式串与子串匹配失败
  return -1;
}

测试:


六.最后

不经一番寒彻骨,怎得梅花扑鼻香。


 

相关文章
|
1月前
|
算法
【算法】滑动窗口——找到字符串中所有字母异位词
【算法】滑动窗口——找到字符串中所有字母异位词
|
23天前
|
算法 C++
A : DS串应用–KMP算法
这篇文章提供了KMP算法的C++实现,包括计算模式串的next数组和在主串中查找模式串位置的函数,用于演示KMP算法的基本应用。
|
1月前
|
算法 Java
掌握算法学习之字符串经典用法
文章总结了字符串在算法领域的经典用法,特别是通过双指针法来实现字符串的反转操作,并提供了LeetCode上相关题目的Java代码实现,强调了掌握这些技巧对于提升算法思维的重要性。
|
1月前
|
算法
KMP算法
KMP算法
11 0
|
2月前
|
自然语言处理 算法 搜索推荐
字符串相似度算法完全指南:编辑、令牌与序列三类算法的全面解析与深入分析
在自然语言处理领域,人们经常需要比较字符串,这些字符串可能是单词、句子、段落甚至是整个文档。如何快速判断两个单词或句子是否相似,或者相似度是好还是差。这类似于我们使用手机打错一个词,但手机会建议正确的词来修正它,那么这种如何判断字符串相似度呢?本文将详细介绍这个问题。
234 1
|
2月前
|
数据采集 算法 JavaScript
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
JavaScript字符串搜索涵盖`indexOf`、`includes`及KMP算法。`indexOf`返回子字符串位置,`includes`检查是否包含子字符串。KMP是高效的搜索算法,尤其适合长模式匹配。示例展示了如何在数据采集(如网页爬虫)中使用这些方法,结合代理IP进行安全搜索。代码示例中,搜索百度新闻结果并检测是否含有特定字符串。学习这些技术能提升编程效率和性能。
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
|
1月前
|
算法 C++
惊爆!KPM算法背后的秘密武器:一行代码揭秘字符串最小周期的终极奥义,让你秒变编程界周期大师!
【8月更文挑战第4天】字符串最小周期问题旨在找出字符串中最短重复子串的长度。KPM(实为KMP,Knuth-Morris-Pratt)算法,虽主要用于字符串匹配,但其生成的前缀函数(next数组)也可用于求解最小周期。核心思想是构建LPS数组,记录模式串中每个位置的最长相等前后缀长度。对于长度为n的字符串S,其最小周期T可通过公式ans = n - LPS[n-1]求得。通过分析周期字符串的特性,可证明该方法的有效性。提供的C++示例代码展示了如何计算给定字符串的最小周期,体现了KPM算法在解决此类问题上的高效性。
49 0
|
2月前
|
算法 Java
KMP算法详解及其在字符串匹配中的应用
KMP算法详解及其在字符串匹配中的应用
|
3月前
|
人工智能 算法 BI
一篇文章讲明白KMP算法(俗称看毛片算法)
一篇文章讲明白KMP算法(俗称看毛片算法)
34 0
|
15天前
|
算法 BI Serverless
基于鱼群算法的散热片形状优化matlab仿真
本研究利用浴盆曲线模拟空隙外形,并通过鱼群算法(FSA)优化浴盆曲线参数,以获得最佳孔隙度值及对应的R值。FSA通过模拟鱼群的聚群、避障和觅食行为,实现高效全局搜索。具体步骤包括初始化鱼群、计算适应度值、更新位置及判断终止条件。最终确定散热片的最佳形状参数。仿真结果显示该方法能显著提高优化效率。相关代码使用MATLAB 2022a实现。