KPM算法

article/2025/10/9 8:30:35

算法 字符串匹配之朴素算法和KMP算法及JAVA代码实现

2017年06月02日 10:31:12

阅读数:941

暴力匹配算法

假设现在我们面临这样一个问题:有一个文本串S,和一个模式串P,现在要查找P在S中的位置,怎么查找呢?

如果用暴力匹配的思路,并假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置,则有:

  • 如果当前字符匹配成功(即S[i] == P[j]),则i++,j++,继续匹配下一个字符;

  • 如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0。相当于每次匹配失败时,i 回溯,j 被置为0。

example:

如果给定文本串S“BBC ABCDAB ABCDABCDABDE”,和模式串P“ABCDABD”,现在要拿模式串P去跟文本串S匹配,整个过程如下所示:

  1. S[0]为B,P[0]为A,不匹配,模式串要往右移动一位

这里写图片描述 
2. S[1]跟P[0]还是不匹配,模式串继续右移

这里写图片描述 
3.直到S[4]跟P[0]匹配成功(i=4,j=0)此时比较两个字符串的下一个字符

这里写图片描述 
4. 匹配成功 继续比较两个字符串的下一个字符

这里写图片描述 
5. 直到S[10]为空格字符,P[6]为字符D(i=10,j=6),因为不匹配,将模式串右移一位继续比较

这里写图片描述 
6. 继续按照上述方法进行比较

这里写图片描述

JAVA代码实现

/*** 暴力匹配算法** @param sStr 父串* @param dStr 子串* @return 子串在父串中下标index[int]*/public static int violentMatch(String sStr, String dStr) {int sLength = sStr.length();int dLength = dStr.length();int sIndex = 0, dIndex = 0;while (sIndex < sLength && dIndex < dLength) {//当前字符匹配if (sStr.charAt(sIndex) == dStr.charAt(dIndex)) {//父串和子串同时后移一个字符sIndex++;dIndex++;} else {//不匹配则sIndex回溯,dIndex被置为0sIndex = sIndex - (dIndex - 1);dIndex = 0;}}if (dIndex == dLength) {return sIndex - dLength;}return -1;}

测试一下

/*测试数据*/String onceStr = "eeeabceee";String noneStr = "adfsdf";String mutiStr1 = "eeeeeeabceeeabc";String mutiStr2 = "eeeeeeabceeeabc";String destStr = "abc";String replaceStr = "XXX";/*输出格式*/String indexPattern = "{0} 在 {1} 首次出现的位置: {2}";String indexesPattern = "{0} 在 {1} 出现的所有位置:{2}";String replacePattern = "使用 {0} 替换 {1} 中的 {2}: {3}";/*===========测试暴力匹配算法===========*///1.测试出现一次情况index = StringMatcher.violentMatch(onceStr, destStr);System.out.println(MessageFormat.format(indexPattern, destStr, onceStr, index));//2.测试出现多次情况index = StringMatcher.violentMatch(mutiStr1, destStr);System.out.println(MessageFormat.format(indexPattern, destStr, mutiStr1, index));

输出结果

abc 在 eeeabceee 首次出现的位置: 3
abc 在 eeeeeeabceeeabc 首次出现的位置: 6
  • 1
  • 2
  • 3

KMP算法

KMP的算法流程:

假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置

  • 如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++,继续匹配下一个字符;

  • 如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]。此举意味着失配时,模式串P相对于文本串S向右移动了j - next [j] 位。

换言之,当匹配失败时,模式串向右移动的位数为:失配字符所在位置 - 失配字符对应的next 值(next 数组的求解会在下文的3.3.3节中详细阐述),即移动的实际位数为:j - next[j],且此值大于等于1。

很快,你也会意识到next 数组各值的含义:代表当前字符之前的字符串中,有多大长度的相同前缀后缀。例如如果next [j] = k,代表j 之前的字符串中有最大长度为k 的相同前缀后缀。

此也意味着在某个字符失配时,该字符对应的next 值会告诉你下一步匹配中,模式串应该跳到哪个位置(跳到next [j] 的位置)。如果next [j] 等于0或-1,则跳到模式串的开头字符,若next [j] = k 且 k > 0,代表下次匹配跳到j 之前的某个字符,而不是跳到开头,且具体跳过了k 个字符。

这里写图片描述

这里写图片描述

转换成JAVA代码就是

/*** KMP匹配算法** @param sStr 父串* @param dStr 子串* @return 子串在父串中下标index[int]*/public static int KMPMatch(String sStr, String dStr) {int sLength = sStr.length();int dLength = dStr.length();int sIndex = 0, dIndex = 0;int[] next = getNextArray(dStr);while (sIndex < sLength && dIndex < dLength) {//当前字符匹配if (dIndex==-1||sStr.charAt(sIndex) == dStr.charAt(dIndex)) {//父串和子串同时后移一个字符sIndex++;dIndex++;} else {//不匹配 sIndex不变dIndex取next[j]dIndex = next[dIndex];}}if (dIndex == dLength) {return sIndex - dLength;}return -1;}

问题的关键是如何求next数组

求解next数组

  1. 寻找前缀后缀最长公共元素长度

如果给定的模式串为“abab”,那么它的各个子串的前缀后缀的公共元素的最大长度如下表格所示:

这里写图片描述

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

这里写图片描述

  1. 求next数组

next 数组考虑的是除当前字符外的最长相同前缀后缀,所以通过第①步骤求得各个前缀后缀的公共元素的最大长度后,只要稍作变形即可:将第①步骤中求得的值整体右移一位,然后初值赋为-1,如下表格所示:

这里写图片描述

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

这里写图片描述

JAVA代码实现

/*** 获取next数组** @param destStr 目的字符串* @return next数组*/public static int[] getNextArray(String destStr) {int[] nextArr = new int[destStr.length()];nextArr[0] = -1;int k = -1, j = 0;while (j < destStr.length() - 1) {if (k == -1 || (destStr.charAt(j) == destStr.charAt(k))) {++k;++j;nextArr[j] = k;} else {k = nextArr[k];}}return nextArr;}

测试

/*===========测试KMP匹配算法===========*/
 

index = StringMatcher.KMPMatch(onceStr, destStr); System.out.println(MessageFormat.format(indexPattern, destStr, onceStr, index)); index = StringMatcher.violentMatch(mutiStr1, destStr); System.out.println(MessageFormat.format(indexPattern, destStr, mutiStr1, index));

测试结果

abc 在 eeeabceee 首次出现的位置: 3
abc 在 eeeeeeabceeeabc 首次出现的位置: 6

 


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

相关文章

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

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

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的路径&…