【C#】KPM算法解决字符串匹配问题

article/2025/10/9 8:31:02

KPM算法解决字符串匹配问题

  • 什么是KPM算法
  • 步骤
    • Ⅰ根据《最大长度表》部分匹配表(next)
      • 寻找最长前缀后缀
    • Ⅱ 根据 部分匹配表 进行匹配
  • 代码实现

什么是KPM算法

  Knuth-Morris-Pratt 字符串查找算法,简称为 “KMP算法”,常用于在一个文本串S内查找一个模式串P 的出现位置,这个算法由Donald Knuth、Vaughan Pratt、James H. Morris三人于1977年联合发表,故取这3人的姓氏命名此算法。

  KMP方法算法就利用之前判断过信息,通过一个next数组,保存模式串中前后最长公共子序列的长度,每次回溯时,通过next数组找到,前面匹配过的位置,省去了大量的计算时间。

  • KPM的使用场景:模式串在文本串是否出现过,如果出现过,最早出现的位置

步骤

Ⅰ根据《最大长度表》部分匹配表(next)

  对于P = p0 p1 ...pj-1 pj,寻找模式串P中长度最大且相等的前缀和后缀。如果存在p0 p1 ...pk-1 pk = pj- k pj-k+1...pj-1 pj,那么在包含pj的模式串中有最大长度为k+1的相同前缀后缀。
  举个例子,如果给定的模式串为“abab”,那么它的各个子串的前缀后缀的公共元素的最大长度如下表格所示:

在这里插入图片描述
  比如对于字符串aba来说,它有长度为1的相同前缀后缀a;而对于字符串abab来说,它有长度为2的相同前缀后缀ab(相同前缀后缀的长度为k + 1,k + 1 = 2)。

结论:最大前缀后缀元素长度所得到的数组就是我们所需要的 “部分匹配表”

寻找最长前缀后缀

  • 如果给定的模式串是:“ABCDABD”,从左至右遍历整个模式串,其各个子串的前缀后缀分别如下表格所示:
    在这里插入图片描述

Ⅱ 根据 部分匹配表 进行匹配

  匹配失配,j = next [j],模式串向右移动的位数为:j - next[j]。换言之,当模式串的后缀pj-k pj-k+1, ..., pj-1跟文本串si-k si-k+1, ..., si-1匹配成功,但pjsi匹配失败时,因为next[j] = k,相当于在不包含pj的模式串中有最大长度为k 的相同前缀后缀,即p0 p1 ...pk-1 = pj-k pj-k+1...pj-1,故令j = next[j],从而让模式串右移j - next[j]位,使得模式串的前缀p0 p1, ..., pk-1对应着文本串si-k si-k+1, ..., si-1,而后让pksi继续匹配。如下图所示:

在这里插入图片描述
  KMP的next数组相当于告诉我们:
    当模式串中的某个字符跟文本串中的某个字符匹配失配时,模式串下一步应该跳到哪个位置。如模式串中在j处的字符跟文本串在i处的字符匹配失配时,下一步用next [j]处的字符继续跟文本串i 处的字符匹配,相当于模式串向右移动j - next[j]位。

代码实现

字符串匹配问题:
有一个字符串 str1=““上海自来水来自海上””,和一个子串 str2=“自来水”。
现在要判断str1是否含有str2, 如果存在,就返回第一次出现的位置, 如果没有,则返回-1

static void Main(string[] args)
{string str1 = "上海自来水来自海上";string str2 = "自来水";// 得出 部分匹配表int[] next = KPMNext(str2);// 根据 得出的 部分匹配表的 next 数组进行匹配,int index = KPMSearch(str1, str2, next);Console.WriteLine(index);
}/// <summary>
/// 获取一个字符串的部分匹配值表
/// </summary>
/// <param name="dest"></param>
/// <returns></returns>
static int[] KPMNext(string dest)
{// 初始化 数组大小int[] next = new int[dest.Length];// 字符串长度为1,部分匹配值就为0next[0] = 0;for (int i = 1, j = 0; i < dest.Length; i++){while (j > 0 && dest[i] != dest[j]){j = next[j - 1];}if (dest[i] == dest[j]){j++;}next[i] = j;}return next;
}/// <summary>
/// kmp搜索
/// </summary>
/// <param name="str1">源字符串</param>
/// <param name="str2">子字符串</param>
/// <param name="next">部分匹配表</param>
/// <returns></returns>
static int KPMSearch(string str1, string str2, int[] next)
{for (int i = 0, j = 0; i < str1.Length; i++){while (j > 0 && str1[i] != str2[j]){j = next[j - 1];}if (str1[i] == str2[j]){j++;}if (j == str2.Length){return i - j + 1;}}return -1;
}

http://chatgpt.dhexx.cn/article/3lc4JnDC.shtml

相关文章

串的匹配 (KPM算法由来引导)

前言: 引入 KPM 算法的前提是 , B-F算法中,匹配失败后不必完全从头再来 , 找到可以利用的信息 , 可以进行跳跃性匹配 下面 , 我们对字符串匹配的一些思路进行剖析: 开始匹配的操作 ,我们会让 目标串 s , 和 模式串进行对齐,就像如图所示: 我们当然是从串 t 的头结点开始对比 对…

KPM匹配算法

KPM匹配算法 不管在工作中还是学习中经常会遇到串的模式匹配&#xff0c;一般来说&#xff0c;串的模式匹配算法主要是两种【朴素模式匹配和KPM模式匹配】一种改良【KPM的改良】&#xff0c;下面先看一下朴素模式匹配&#xff1a;朴素模式匹配主要思想比较简单也比较粗暴&…

KPM算法

算法 字符串匹配之朴素算法和KMP算法及JAVA代码实现 2017年06月02日 10:31:12 阅读数&#xff1a;941 暴力匹配算法 假设现在我们面临这样一个问题&#xff1a;有一个文本串S&#xff0c;和一个模式串P&#xff0c;现在要查找P在S中的位置&#xff0c;怎么查找呢&#xff1…

Python KPM算法

知识点说明&#xff1a; 先说前缀&#xff0c;和后缀吧 比如有一个串&#xff1a;abab 则在下标为3处的&#xff08;前缀和后缀都要比下标出的长度小1&#xff0c;此处下标为3出的长度是4&#xff09; 前缀为&#xff1a;a,ab,aba 后缀为&#xff1a;b,ba,bab 一、要获取…

KPM算法——数据结构|复习局|串|复杂模式匹配算法|二维数组解决KPM

数据结构复习局——KPM算法 何为KPM&#xff1f;事先规则状态匹配dp——状态转移图状态X获得dp数组值看看图再理解下 写在前面&#xff1a; 本文仅为作者个人学习记录&#xff0c;详细具体内容参考自知乎大佬labuladong &#x1f448;点击与大佬&#x1f93a;击剑&#x1f93a;…

KMP算法原理及实例

KMP是为了解决串的匹配问题。 一、基础知识 1、概念 1.串的匹配问题&#xff1a;就是在一个长的主串s中找到另一个的短的子串t。 2.目标串&#xff08;主串\文本串&#xff09;&#xff1a;被匹配的母串&#xff0c;串s被称为目标串。 3.模式串(子串&#xff09;&#xff1a…

KPM算法思想及实现

一、比较暴力算法和KMP算法 1、暴力算法&#xff1a; 双指针遍历主串和子串&#xff0c;当发现主串和子串不匹配时&#xff0c;双指针同时回溯 2、KMP算法&#xff1a; 双指针遍历主串和子串&#xff0c;当发现主串和子串不匹配时&#xff0c;通过比较子串的next数组只回溯…

正定矩阵的性质

正定矩阵的定义&#xff1a;若矩阵A是n阶方阵&#xff0c;并且它的二次型大于0&#xff0c;即&#xff0c;则矩阵A是正定矩阵。 正定矩阵的性质&#xff1a; 正定矩阵的所有特征值都为正数。正定矩阵行列式为正数两个正定矩阵的和为正定矩阵&#xff08;两个正定矩阵的乘积不…

顺序主子式

设A为 阶矩阵&#xff0c;子式 称为A的i阶顺序主子式。 [1] 对于 阶的矩阵A&#xff0c;其共有n阶顺序主子式&#xff0c;即矩阵A的顺序主子式由 共n个行列式按顺序排列而成。

【矩阵论笔记】平方根分解

定义 例子 首先判断顺序主子式。 R矩阵每一行除以对角元 平方根分解推导 因为A的分解是唯一的&#xff0c;可以得到 L R T LR^{T} LRT 例题 待定系数法

MATLAB_数值计算_用平方根法解线性方程组—(Cholesky分解)

利用对称正定矩阵的乔累斯基分解求解对称正定方程组的方法称为平方根法对称正定矩阵A的对角元为正实对称矩阵A正定的充要条件是A的所有特征值为正对称正定矩阵非奇异&#xff0c;其逆亦为对称正定矩阵实对称矩阵A正定的充要条件是A的所有顺序主子式为正正定矩阵的顺序主子阵是正…

正定与半正定矩阵,判别的方法不能混用,否则出错

坑&#xff1a;特征值有0可以知道该矩阵不可能正定&#xff0c;那可以用顺序主子式判断是否为半正定吗&#xff1f; 答案&#xff1a;不能 例子&#xff1a;A,特征值为一个0&#xff0c;两个正数>那就是半正定啦呀 但是&#xff0c;主子式二阶小于0那就不正定了呀两种方法…

线性代数【11】二次型

前言&#xff1a; 矩阵表达的是线性关系的方程组&#xff0c;但是&#xff0c;客官世界&#xff0c;是包括稍微复杂的&#xff0c;二次方程。 尤其几何中&#xff0c;有二次曲线&#xff0c;二次型&#xff0c;就是一个多元函数&#xff0c;是多个变量的二次&#xff0c;齐次…

Lyapunov稳定性分析1(正定函数、二次型正定判定)

一、 正定函数 1.1 定义&#xff1a; 令V(x)是向量x的标量函数&#xff0c;S是x空间包含原点的封闭有限区域。如果对于S中的所有x&#xff0c;都有&#xff1a; 则V(x)是正定的&#xff08;半正定&#xff09;。正定函数更直观的描述如下图所示&#xff1a; 如果条件(3&a…

牛顿法为什么要保证Hessian矩阵正定

牛顿法为什么要保证Hessian矩阵正定&#xff1a; 实际中&#xff0c;需要求出Hessian的逆矩阵&#xff0c;只有正定矩阵&#xff0c;才可以求出逆矩阵。 正定矩阵&#xff1a;特征值全大于0&#xff1b;各阶主子式全大于0.

正定矩阵的相关知识

一、正定矩阵的定义&#xff1a;若矩阵A是n阶方阵&#xff0c;并且它的二次型大于0&#xff0c;即 则矩阵A是正定矩阵。 二、正定矩阵的性质&#xff1a; 1.正定矩阵的所有特征值都为正数。 2.正定矩阵行列式为正数 3.两个正定矩阵的和为正定矩阵&#xff08;两个正定矩阵的乘…

顺序主子式的英文翻译(定义)

顺序主子式的英文翻译&#xff08;定义&#xff09; 为了查明顺序主子式的英文翻译&#xff0c;我在国内知网翻译助手、金山词霸等诸多翻译系统查了一下&#xff0c;给出的答案不外乎以下几个答案。 &#xff08;知网翻译助手的答案&#xff09; 我喜欢刨根问底&#xff0c;很明…

030 正定二次型及判别法之定义法、特征值法、顺序主子式法

030 正定二次型及判别法之定义法、特征值法、顺序主子式法

matlab-线性代数 det 各阶主子式、余子式、代数余子式

2019独角兽企业重金招聘Python工程师标准>>> matlab : R2018a 64bit     OS : Windows 10 x64typesetting : Markdown    blog : my.oschina.net/zhichengjiu    gitee : gitee.com/zhichengjiu 各阶主子式 code clear clca=[1 2 3;4 5 6;6 7 8…

主子式、顺序主子式、余子式、代数余子式

K阶子式 [ 1 ] ^{[1]} [1] (Minor) 以3阶行列式为例&#xff1a; ∣ a 1 a 2 a 3 b 1 b 2 b 3 c 1 c 2 c 3 ∣ \left| \begin{array} {ccc} a_1 & a_2 & a_3 \\ b_1 & b_2 & b_3\\ c_1 & c_2 & c_3 \end{array} \right| ∣∣∣∣∣∣​a1​b1​c1​​…