一文帮你搞懂 | 串的模式匹配-朴素匹配和KMP算法及优化

简介: 目录 朴素模式匹配算法KMP算法 求模式串的next数组总结:求模式串的next数组KMP算法优化

目录

 

朴素模式匹配算法

KMP算法

求模式串的next数组

总结:求模式串的next数组

KMP算法优化


朴素模式匹配算法

什么是模式匹配

串的模式匹配就是在子串中找到与模式串相同的子串,并返回其所在位置。

int idex(SString S,SString T){
  int k = 1;
  int i = k, j = 1;
  while(i <= S.length && j <= T.length)
  {
    if(S.ch[i] == T.ch[j])
    {
      i++;   
      j++;      //继续比较后面字符 
    }
    else{
      k++;    //检查下一个子串 
      i = k;
      j = 1;
    }
    if(j > T.length)
      return k;
    else
      return 0;
  } 
} 

为什么会出现return 0的情况,假设T为a  o  o,那么会出现 i 大于串的长度 ,而 j 没有超出串的长度,则跳出循环,匹配失败

image.png

朴素算法算法性能分析:

若模式串长度为m,主串长度为n,则

匹配成功的最好时间复杂度:O(m)

匹配失败的最好时间复杂度:O(n-m+1)=)(n-m)约等于O(n)

image.png

如果出现一下情况

image.png

最坏的时间复杂度是O(mn)

KMP算法

举个例子如下图,子串是google,主串是googlogooglegoolo

image.png

我们看看当我进行完前面的操作后,是否需要继续重i = 2, j = 1开始看起呢

看下面的例子

image.png

当我们发现j = 6的时候我们知道了 i  现在所指向一定不等于 e ,由于前面我们进行判断过,所以我们知道了i 不需要从 6 - 10开始匹配看,因为前面我们看过了我们不用回溯,况与 j = 1的时候比较就行。


移动之后,如果该字直接可以让i = 11的情符是  g 那么让那么i++ , j++ 。如果该字符不是 g  ,那么让·i++ ,j = 1 。4


如下图

image.png

第二种情况看下面例子

image.png

如果前面几个都进行了匹配但是突然发现当 j = 5的时候与i = 9的地方不匹配,那么回溯的时候,由于前面几个进行了匹配,i 不用回到 6,7的位置,当 i 到8的位置是可以的,因为我们只能确定 i= 9的位置不等于 I ,但是我们不确定是不是 o ,所以我们可以把 i 移到 8的位置,而   j  移到 8的位置,总的来说,就是如果  j = 5发生不匹配,那么  j 回到 2,而 i 到 8。

image.png

第三种情况看下面的例子

image.png

当 j = 4与i = 6,发生了不匹配 ,i = 4与 i = 5情况由于都是 o,一定不和  g 匹配,所以跳过,应该从i = 6 开始(但是实际上,i = 6 与 g 匹配过肯定不等于 g,这个情况先不考虑)


若 j = 4 的时候发生不匹配,应该让 j = 1,i = 6 。


第四种看下面的例子

image.png

如果 i = 5的时候,与 j = 3的时候不匹配,同样的只能确定 i = 5的位置不等于o,不能确定是否等于g ,所以如果 j = 3的时候,j 退到 j = 1,而 i 的位置不变

image.png

最后一种情况

image.png

如果 j  = 2的时候与 i = 4的时候不匹配,那么我们让 j = 1,i = 4。

汇总一下

image.png

我们把这些情况放到表格中去

这个表格叫next[7]

0 1 2 3 4 5 6
0 1 1 1 2 1

当 j = k ,且发现字符不匹配的时候,令  j = next[k] 来用

g o o g l e
1 2 3 4 5 6

 

代码

int Index_KMP(SString S,SString T,int next[]){
  int i = 1, j = 1;
  while(i <= S.length && j <= T.length){
    if(j == 0 || S.ch[i] == T.ch[i]){
      ++i;
      ++j;                 //继续比较后继字符
    }
    else{
      j = next[j];        //模式串向右移
    }
    if(j > T.length){      //匹配成功
      return  i - T.lenght;
    }
    else 
        return 0;
  }
}

注意:

1、j = 0 的情况是由于当  j = 1的时候  next [ j ]等于0,然后 j ++,变成 j = 1,i ++ 。

2、这里面 ++ j 与 ++ i 和 j ++ 与 i ++ 效果是一样的


求模式串的next数组

看下面的例子

image.png

当 j =  6匹配失败的时候,它的next[ 6 ] = 3

image.png

在看这个情况

image.png

当 i = 7匹配失败的时候 ,让 j 指向 j = 5 的位置,所以它的next[7] = 5

image.png

在看这个例子

image.png

当 j = 5 匹配失败的时候,把字符往右移一格

image.png

同样的也可以匹配到,我们让next [5] = 4 。虽然继续往后移主串与模式串仍能匹配,我们应该选择匹配长度最大的

继续看下一种情况

image.png

当  j = 5 不匹配的时候我们应该让 next [ j ] = 1

image.png

最后在看这个例子(为什么next[1] = 0)

image.png

当 j = 1,就匹配失败的时候  我们可以让   j  设置为 0,然后  j 与  i 同时 ++

即对于任何串都可以让 next [ 1 ] = 0

image.png

总结:求模式串的next数组

如果你没看懂上面的操作,没关系,只要知道如下操作就行

image.png

串的前缀:包含第一个字符,且不包含最后一个字符的子串.


串的后缀:包含最后一个字符,且不包含第一个字符的子串.


当第 j 个字符匹配失败,由前 1 --  j - 1个字符组成的串记为S,则:next [j] = S的最长相等的前后缀长度+ 1 。


特别 next[1] = 0;


下面通过一个列子来看


当模式串为 'a b a b a a'


序号  j 1 2 3 4 5 6

模式串 a b a b a a

next [j] 0 1 1 2 3 4

j 为1的时候无可置疑的选择next[ 1 ] =  0,


j 为2的时候ab相等前缀和后缀长度都为 0 ,next [ 2 ] = 1    (0+1)


j 为3的时候aba,前缀为a,后缀为b,不相等,next [ 3 ] = 1   ( 0+1)


j 为4的时候abab,前缀为a,后缀为a的时候最长相等子串,next [4] = 2    (1+1)


j 为5的时候ababa ,当前缀为ab,后缀为ab的时候为最长相等子串,next [5] = 3  ( 2+ 1)


j 为6的时候ababaa,当前缀为aba,后缀为aba的时候为最长相等子串,next [6]= 4  (3+ 1)

image.png

求模式串T的next数组

void get_next(SString T,int next[])
{
  int i = 1,j = 0;
  next[1] = 0;
  while(i < T.length){
    if(j ==0 || T.ch[i] == ch[j] )
    {
       ++i;
       ++j;
       next[i] = j; 
    } 
    else  
      j = next[j];
  }
}

上面的参考,其实也可以这样写

void get_next(String T)
{
  int i = 1,j = 0;
  next[1] = 0;
  while(i < T.length){
    if(j ==0 || T.ch[i] == ch[j] )
    {
       next[++i] = ++j; 
    } 
    else  
      j = next[j];
  }
}

KMP算法

int Index KMP(SSTring S,SString T){
  int i = 1,j = 1;
  int next[T.length+1];
  get_next(T,next);
  while(i<=S.length&&j<=T.length){
    if(j==0 || S.ch[i] == T.ch[j]){
      ++i;
      ++j;
    }
    else 
      j = next[j];
  } 
  if(j> T.length)
     return i - T.length;
  else 
     return 0;
} 

image.png

KMP算法优化

image.png

根据上面我们发现有这个情况,就是我们知道 i 指向 4 的位置 不等于g,但是我们仍有 next [ 4 ] = 1 ,继续比较了g,有点重复,所以我们可以作出优化,让next[ 4 ] = 0,j = 0 。 这样 j++,i++,让 j = 1 , 与 i = 5 进行比较了。

image.png

nextval数组的求法

先算出next数组
先令nextva[ 1 ] = 0
for (int j = 2; j <= T.lenght; j++){
           if(T.ch[next[ j ] == T.ch[j)
                       nextval[ j ] = nextval [next [ j ] ];
           else 
                       nextval [ j ] = next[ j ];
] }


相关文章
|
12天前
|
机器学习/深度学习 算法
基于改进遗传优化的BP神经网络金融序列预测算法matlab仿真
本项目基于改进遗传优化的BP神经网络进行金融序列预测,使用MATLAB2022A实现。通过对比BP神经网络、遗传优化BP神经网络及改进遗传优化BP神经网络,展示了三者的误差和预测曲线差异。核心程序结合遗传算法(GA)与BP神经网络,利用GA优化BP网络的初始权重和阈值,提高预测精度。GA通过选择、交叉、变异操作迭代优化,防止局部收敛,增强模型对金融市场复杂性和不确定性的适应能力。
145 80
|
3天前
|
机器学习/深度学习 人工智能 算法
机器学习算法的优化与改进:提升模型性能的策略与方法
机器学习算法的优化与改进:提升模型性能的策略与方法
41 13
机器学习算法的优化与改进:提升模型性能的策略与方法
|
16小时前
|
机器学习/深度学习 数据采集 算法
基于GA遗传优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
本项目基于MATLAB2022a实现时间序列预测,采用CNN-GRU-SAM网络结构。卷积层提取局部特征,GRU层处理长期依赖,自注意力机制捕捉全局特征。完整代码含中文注释和操作视频,运行效果无水印展示。算法通过数据归一化、种群初始化、适应度计算、个体更新等步骤优化网络参数,最终输出预测结果。适用于金融市场、气象预报等领域。
基于GA遗传优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
|
6天前
|
机器学习/深度学习 算法
基于遗传优化的双BP神经网络金融序列预测算法matlab仿真
本项目基于遗传优化的双BP神经网络实现金融序列预测,使用MATLAB2022A进行仿真。算法通过两个初始学习率不同的BP神经网络(e1, e2)协同工作,结合遗传算法优化,提高预测精度。实验展示了三个算法的误差对比结果,验证了该方法的有效性。
|
8天前
|
机器学习/深度学习 数据采集 算法
基于PSO粒子群优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
本项目展示了基于PSO优化的CNN-GRU-SAM网络在时间序列预测中的应用。算法通过卷积层、GRU层、自注意力机制层提取特征,结合粒子群优化提升预测准确性。完整程序运行效果无水印,提供Matlab2022a版本代码,含详细中文注释和操作视频。适用于金融市场、气象预报等领域,有效处理非线性数据,提高预测稳定性和效率。
|
9天前
|
机器学习/深度学习 算法 索引
单目标问题的烟花优化算法求解matlab仿真,对比PSO和GA
本项目使用FW烟花优化算法求解单目标问题,并在MATLAB2022A中实现仿真,对比PSO和GA的性能。核心代码展示了适应度计算、火花生成及位置约束等关键步骤。最终通过收敛曲线对比三种算法的优化效果。烟花优化算法模拟烟花爆炸过程,探索搜索空间,寻找全局最优解,适用于复杂非线性问题。PSO和GA则分别适合快速收敛和大解空间的问题。参数调整和算法特性分析显示了各自的优势与局限。
|
13天前
|
缓存 算法 搜索推荐
Java中的算法优化与复杂度分析
在Java开发中,理解和优化算法的时间复杂度和空间复杂度是提升程序性能的关键。通过合理选择数据结构、避免重复计算、应用分治法等策略,可以显著提高算法效率。在实际开发中,应该根据具体需求和场景,选择合适的优化方法,从而编写出高效、可靠的代码。
25 6
|
19天前
|
机器学习/深度学习 前端开发 算法
婚恋交友系统平台 相亲交友平台系统 婚恋交友系统APP 婚恋系统源码 婚恋交友平台开发流程 婚恋交友系统架构设计 婚恋交友系统前端/后端开发 婚恋交友系统匹配推荐算法优化
婚恋交友系统平台通过线上互动帮助单身男女找到合适伴侣,提供用户注册、个人资料填写、匹配推荐、实时聊天、社区互动等功能。开发流程包括需求分析、技术选型、系统架构设计、功能实现、测试优化和上线运维。匹配推荐算法优化是核心,通过用户行为数据分析和机器学习提高匹配准确性。
60 3
|
19天前
|
算法
PAI下面的gbdt、xgboost、ps-smart 算法如何优化?
设置gbdt 、xgboost等算法的样本和特征的采样率
41 2
|
1月前
|
算法
基于GA遗传算法的PID控制器参数优化matlab建模与仿真
本项目基于遗传算法(GA)优化PID控制器参数,通过空间状态方程构建控制对象,自定义GA的选择、交叉、变异过程,以提高PID控制性能。与使用通用GA工具箱相比,此方法更灵活、针对性强。MATLAB2022A环境下测试,展示了GA优化前后PID控制效果的显著差异。核心代码实现了遗传算法的迭代优化过程,最终通过适应度函数评估并选择了最优PID参数,显著提升了系统响应速度和稳定性。
153 15

热门文章

最新文章