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

article/2025/10/8 15:54:14

数据结构复习局——KPM算法

    • 何为KPM?
    • 事先规则
    • 状态
    • 匹配
    • dp——状态转移图
    • 状态X
    • 获得dp数组值
    • 看看图再理解下


写在前面:
本文仅为作者个人学习记录,详细具体内容参考自知乎大佬labuladong 👈点击与大佬🤺击剑🤺


话不多说,上代码

public class KMP {private int[][] dp;private String pat;public KMP(String pat) {this.pat = pat;int M = pat.length();// dp定义为:dp[状态][字符] = 下个状态//在相应的状态、字符定位位置的dp,其值指代下一个达到的状态dp = new int[M][256];// 初始化://只有在状态0处,遇到第一个字符时,dp才会为1进入状态1dp[0][pat.charAt(0)] = 1;// X 初始为状态  0int X = 0;// 构建状态转移图for (int j = 1; j < M; j++) {for (int c = 0; c < 256; c++)dp[j][c] = dp[X][c];//此处j从1开始,找到状态1想要进入状态2时遇到的字符dp[j][pat.charAt(j)] = j + 1;// 更新状态XX = dp[X][pat.charAt(j)];}}public int search(String txt) {int M = pat.length();int N = txt.length();// pat 的初始状态为 0int j = 0;for (int i = 0; i < N; i++) {// 计算 pat 的下一个状态j = dp[j][txt.charAt(i)];// 到达终止态,返回结果if (j == M) return i - M + 1;}// 没到达终止态,匹配失败return -1;}
}

何为KPM?

命名来自算法发表团队成员姓名,简写为KPM。
KPM算法与相对于简单匹配算法相比较,更为高效的模式匹配算法
相比于简单匹配算法一步一匹配,一错全回退的不足之处,KPM算法优化了匹配模式串的效率。
本文介绍的KPM不同于课本所讲的,采用二维数组的方式来进行优化。
(不懂简单匹配算法的,还不速速去学~)


事先规则

首先定义一下,方便理解:
pat——模式串,即需要从母串中匹配出的子串,长度M
txt——文本串,被匹配的母串,长度N
所谓KMP算法,即区别于简单模式匹配算法,永不退回TXT指针i,不走回头路。


状态

将母串匹配子串的过程,理解为状态的转换

举个例子:

我们这里有一个pat“ABABC”,它的匹配过程是:先找到“A”,找到“A”后查看下一个字符是否是“B”,再看下一个……一直到从母串中匹配出“ABABC”为止。

这个匹配过程,将其理解为状态的转换:没有匹配到pat的任何一个字符叫做状态0,匹配到一个叫状态1,以此类推,即此处举例的字符串,在状态5时完成匹配。


匹配

理解了什么是状态的转换,那么匹配的过程就可以生动的描述为,状态的转换,从状态0一步一步转换到最终态 pat.length()

这里来定义一个二维数组dp——

dp = int[状态值][字符];

此处的二维数组中,行值代表当前的状态值,列值代表所匹配到的字符,而被_该行列值所指定的数组值_,即下一个要达到的状态值*。

到了这里,只需要找到dp = 1 - 5的几组转移关系的状态值和字符了,而dp也就成为了一副状态转移图。

那么其实匹配过程的函数就可以写出来了:

public int search(String txt){int M = pat.length();int N = txt.length();//初始状态下,pat状态为0int j = 0;//遍历txt串for(int i = 0; i < N; i++){//状态j,遇到字符txt[i]//若状态j时,遇到字符为匹配字符,则状态推进,即j+1j = dp[j][txt.charAt(i)];//判断一下是否达到终止态,达到终止态则返回匹配开头的索引if(j == M) return i - M + 1;}//循环结束,遍历txt没达到终止态,则匹配失败return -1}

dp——状态转移图

上述过程理解之后,显而易见的是,需要根据dp数组的信息,在遍历txt时,来进行匹配,确定在状态几时遇到字符c,需要转换到状态几。
再看一次dp的定义:

dp = int[状态值][字符];

显然,dp的状态值与字符不成问题,问题是二者定位得到的数组值

  • 同样pat是“ABABC”时,当处于状态2,即子串匹配到了“AB”的状态,只有下一个字符匹配到“A”时,才可以从状态2推进至状态3,也就得到:dp[2][‘A’] = 3
           AB                     ABAABABC(2)               ABABC(3)
  • 同理可得:当处于状态2却遇到了字符“C”时,需要回退到状态0,重新开始匹配:
            AB                 ABCABABC(2)              ABABC(0)
  • 那么状态回退就一定是回退到0吗?也不尽然——例如👇
            ABAB                 ABABAABABC(4)               ABABC(3)

此处的例子中,虽然状态4没有匹配到想要的字符“C”,但匹配到字符“A”时,算法将其退回至状态3,这里又是什么逻辑呢?


状态X

上述例子中,最后一个为什么可以从状态4回退到状态3呢?细心的朋友可能发现在最开始的代码里,定义了一个状态X

int X = 0;

给其初始化值为0,那么这里的状态X,就是匹配状态永远晚一步的状态,何解?

  • 现有已知逻辑:状态从0——5(此处5代指最终态),匹配字符个数的增多,伴随状态前进状态数增加
  • 从匹配到状态1开始,状态X即有:
  • X = dp[X][txt.charAt(0)]

  • 即:X随着状态转变,状态数+1,X随之+1,并记录下转变前状态
  • 当状态回退时,即回到X记录的之前的状态:
  • dp[j][c] = dp[X][c];

由此,解释了为什么KMP算法不需要txt指针的回退,pat的不断回退代替了txt指针回退,不断与母串进行匹配比较


获得dp数组值

上述逻辑言明,即可得到dp数组中值究竟何来:

public KMP(String pat){this.pat = pat;int M = pat.length();//dp的值为下一个状态dp = new int[M][256];//初始化:状态0时,遇到pat的第一个字符,状态推进到1dp[0][pat.charAt(0)] = 1;//状态X初始为0int X = 0;//当前状态j从1开始for( int j = 1; j < M; j++){for(int c = 0; c < 256; c++){if(pat.charAt(j) == c)dp[j][c] = j + 1;elsedp[j][c] = dp[X][c];}//更新X状态X = dp[X][pat.charAt(j)];	
}

至此,二维数组实现KMP算法所有逻辑及代码梳理结束



看看图再理解下

在这里插入图片描述


记录学习、爬坑经验
究极小白,欢迎大佬指点!
希望可以帮到你!


http://chatgpt.dhexx.cn/article/T7etoypg.shtml

相关文章

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​​…

简单推导:关于矩阵主子式的几点性质

1.名词介绍: 特征多项式&#xff1a;在数域P上的某个方阵A,则行列式即为其特征多项式&#xff0c;简记为; 逆序数&#xff1a;1,2,...n的某个排序相对自然序列相反的个数&#xff1b;记为&#xff1a; 主子式&#xff1a;某个行列式的部分列和部分行&#xff1a;行号和列号一…

Zlib库的安装与使用

在实际应用中经常会遇到要压缩数据的问题&#xff0c;常见的压缩格式有zip和rar,而Linux下那就更多了,bz2,gz,xz什么的都有&#xff0c;单单Linux下的解压和压缩命令就有好多呢&#xff1f;没有什么好不好的。查了资料&#xff0c;应该是zlib这个比较简单好用。应用也广&#x…

zlib安装和使用 linux

zlib的安装与使用 zlib是一个很好的压缩解压缩库&#xff0c;今天我们分别介绍如何在Linux与Windows上安装与使用&#xff1a; 一&#xff1a;Linux平台 首先看看自己的机器上是不是已经安装好zlib了&#xff1a; whereis zlib 如果安装好了&#xff0c;会输出zlib的路径&…

zlib开发笔记(一):zlib库介绍、编译和工程模板

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://blog.csdn.net/qq21497936/article/details/111877005 长期持续带来更多项目与技术分享&#xff0c;咨询请加QQ:21497936、微信&#xff1a;yangsir198808 红胖子(红模仿)的博文大全&#x…

zlib包的下载

zlib包下载地址&#xff1a;http://www.zlib.net/ 这里注意很多帖子都是直接给了具体的连接&#xff0c;比如&#xff1a; wget http://www.zlib.net/zlib-1.2.8.tar.gz 然后... 所以&#xff0c;这里不宜生搬硬套&#xff0c;直接去官网上看&#xff0c;源码地址 ... 然后&am…