浅谈 KMP

简介: KMP算法是一种高效的字符串匹配算法,由Knuth、Morris和Pratt提出。它通过预处理模式串构建next数组,利用匹配失败时的信息减少重复比较,从而提升匹配效率。其时间复杂度为O(m+n),适用于大规模文本匹配场景。

何为 KMP:

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

实现方法:

我们可以发现,KMP 的题目哈希似乎也可以做出来。但是我们可以发现,哈希其实有很多无用功。我们看下图:\

可以发现,在 c 的时候失配(失去匹配)了,但是前面的都符合。如果是哈希,就会像这样匹配:\

很明显,第 $2,4$ 次是无用功,而 KMP 就是为了避免这种无用功。具体是怎么避免的,请往下看。\

我们可以看到上图标红的区域其实是相同的,而第一次符合的就可以与自己本身所对应的先提前比较,避免浪费时间来处理整个的。\

那么怎么处理呢?我们需要用一个 $nxt$ 数组,而我们需要判断的就是,在一个固定的子串中,最长前后缀长度就是可以避免的。\

比如说下图:\aly.tobigirl.com22

我们可以看到这一个字符串 $S$ 所对应的 $nxt$ 数组的数值其实是逐步递增的,那么我们就能得到一个 $\operatorname{getnext}$ 函数,如下:

代码语言:cpp

代码运行次数:0

运行

AI代码解释

void Get_Next(string x){
  int i=0,j=-1;
  nxt[0]=-1;
  while(i<len2){
    if(j==-1||x[i]==x[j]){
      i++;
      j++;
      nxt[i]=j;
    }
    else{
      j=nxt[j];
    }
  }
}

看完后发现并不难,接下来再附上 KMP 那一段代码,主要是运用 $nxt$ 数组,其实想一想并不难。

代码语言:cpp

代码运行次数:0

运行

AI代码解释

void kmp(string x,string y){
  gn(y);
  int i=0,j=0,ans=0;
  while(i<len1){
    if(j==-1||x[i]==y[j]){
      i++;
      j++;
    }
    else{
      j=nxt[j];
    }
    if(j==len2){
      ans++;
      j=nxt[j];
    }
  }
}

例题:

本期例题较少,以理解为主。题单

P3375 【模板】KMP:aly.miithub.com11

模板题,没得说。

代码语言:cpp

代码运行次数:0

运行

AI代码解释

#include<bits/stdc++.h>
using namespace std;
int len1,len2,nxt[1000005];
void gn(string x){
  nxt[0]=-1;
  int i=0,j=-1;
  while(i<len2){
    if(j==-1||x[i]==x[j]){
      i++;
      j++;
      nxt[i]=j;
    }
    else{
      j=nxt[j];
    }
  }
}
void kmp(string x,string y){
  gn(y);
  int i=0,j=0;
  while(i<len1){
    if(j==-1||x[i]==y[j]){
      i++;
      j++;
    }
    else{
      j=nxt[j];
    }
    if(j==len2){
      cout<<i-j+1<<"\n";
      j=nxt[j];
    }
  }
}
int main(){
  string x,y;
  cin>>x>>y;
  len1=x.size();
  len2=y.size();
  kmp(x,y);
  for(int i=1;i<=len2;i++){
    cout<<nxt[i]<<" ";
  }
  return 0;
}

P4824 USACO15FEB Censoring S:

用栈来维护 KMP 的操作,对于后退时不一定要全退,注意就好了。

代码语言:cpp

代码运行次数:0

运行

AI代码解释

#include<bits/stdc++.h>
using namespace std;
int len1,len2,nxt[1000005];
int st[1000005],top,ss[1000005];
void gn(string x){
  nxt[0]=-1;
  int i=0,j=-1;
  while(i<len2){
    if(j==-1||x[i]==x[j]){
      i++;
      j++;
      nxt[i]=j;
    }
    else{
      j=nxt[j];
    }
  }
}
void kmp(string x,string y){
  gn(y);
  int i=0,j=0;
  while(i<len1){
    if(j==-1||x[i]==y[j]){
      st[++top]=i;
      ss[i]=j;
      i++;
      j++;
    }
    else{
      j=nxt[j];
    }
    if(j==len2-1){
      top-=len2;
      j=ss[st[top]];
    }
  }
}
int main(){
  string x,y;
  cin>>x>>y;
  len1=x.size();
  len2=y.size();
  kmp(x,y);
  for(int i=1;i<=top;i++){
    cout<<x[st[i]];
  }
  return 0;
}

P3435 POI 2006 OKR-Periods of Words:

留做练习。

相关文章
|
消息中间件 负载均衡 Kafka
【Kafka面试演练】那Kafka消费者手动提交、自动提交有什么区别?
嗯嗯Ok。分区的作用主要就是为了提高Kafka处理消息吞吐量。每一个topic会被分为多个分区。假如同一个topic下有n个分区、n个消费者,这样的话每个分区就会发送消息给对应的一个消费者,这样n个消费者负载均衡地处理消息。同时生产者会发送消息给不同分区,每个分区分给不同的brocker处理,让集群平坦压力,这样大大提高了Kafka的吞吐量。面试官思考中…
664 4
|
前端开发 JavaScript API
React Draggable 实现拖拽 - 最详细中文教程 - 卡拉云
React Draggable 是 react 生态中,最好用的拖拽实现库之一。如果你的应用中需要实现拖拽功能,可以尝试用 react-draggable,它可以满足多数情况下的拖拽需求,比如一个弹出设置浮窗,可以相互遮挡的容器之类。在所有 react 拖拽库里(即 react dnd, drag and drop),react-draggable 算是把功能性和易用性平衡得最好的拖拽库了。
4253 0
|
存储 C语言 数据格式
计算机组成原理(微课版) -- 第二章 –– 数据信息的表示
计算机组成原理(微课版) -- 第二章 –– 数据信息的表示
|
存储 API 数据库
大模型应用:LlamaIndex、LangChain 与 LangGraph 细节深度、协同应用.24
本文深度解析LlamaIndex、LangChain与LangGraph三大框架:LlamaIndex专注私有数据接入与检索,是LLM的“知识引擎”;LangChain提供模块化组件与链式编排,是基础开发“脚手架”;LangGraph基于状态图实现复杂流程控制,是进阶的“决策大脑”。三者协同构建“数据—工具—流程”全链路LLM应用体系。
636 0
|
存储 弹性计算 人工智能
2025年阿里云企业云服务器ECS选购与配置全攻略
本文介绍了阿里云服务器的核心配置选择方法论,涵盖算力需求分析、网络与存储设计、地域部署策略三大维度。针对不同业务场景,如初创企业官网和AI模型训练平台,提供了具体配置方案。同时,详细讲解了购买操作指南及长期运维优化建议,帮助用户快速实现业务上云并确保高效运行。访问阿里云官方资源聚合平台可获取更多最新产品动态和技术支持。
|
存储 文件存储 数据库
对象存储、块存储、文件存储他们都有什么不通的作用?
对象存储、块存储、文件存储他们都有什么不通的作用?
2929 2
|
小程序 Java 关系型数据库
微信记账小程序
微信记账小程序
1121 0
|
机器学习/深度学习 存储 并行计算
量子计算与材料科学:新材料的发现
量子计算利用量子比特的叠加态和纠缠态,能高效模拟材料的电子结构和性能,加速新材料的发现与优化。从超导材料到磁性材料,再到太阳能电池,量子计算正推动材料科学的革命性进展。未来,量子计算与机器学习的结合将进一步拓展其应用范围,促进材料科学的产业化发展。
1095 1