当前位置: 首页 > news >正文

NC149KMP算法详解

import java.util.*;public class Solution {public int[] BuildPMT(String pattern) {if (pattern == null || pattern.length() == 0) {return new int[0];}int[] pmt = new int[pattern.length()];pmt[0] = 0;  // 第一个字符的PMT值总是0int len = 0;for (int i = 1; i < pattern.length(); ) {if (pattern.charAt(i) == pattern.charAt(len)) {len++;pmt[i] = len;i++;} else {if (len != 0) {len = pmt[len - 1];  // 回退,不是设置pmt[len]} else {pmt[i] = 0;i++;}}}return pmt;}public int kmp(String S, String T) {if (S == null || S.isEmpty() || T == null || T.isEmpty()) {return 0;}int[] pmt = BuildPMT(S);int count = 0;int j = 0;  // pattern指针int i = 0;  // text指针while (i < T.length()) {if (T.charAt(i) == S.charAt(j)) {i++;j++;if (j == S.length()) {count++;j = pmt[j - 1];  // 匹配成功后回退}} else {if (j != 0) {j = pmt[j - 1];} else {i++;}}}return count;}
}

 

1. BuildPMT方法 - 构建部分匹配表

public int[] BuildPMT(String pattern) {if (pattern == null || pattern.length() == 0) {return new int[0];}
  • 功能:检查输入参数是否有效。如果模式串patternnull或空字符串,返回空数组。


 int[] pmt = new int[pattern.length()];pmt[0] = 0;  // 第一个字符的PMT值总是0int len = 0;
  • 功能:初始化部分匹配表pmt,其长度与模式串相同。

  • pmt[0] = 0:单个字符的最长公共前后缀长度为0。

  • len:记录当前最长公共前后缀长度。


 for (int i = 1; i < pattern.length(); ) {if (pattern.charAt(i) == pattern.charAt(len)) {len++;pmt[i] = len;i++;}
  • 功能:当字符匹配时,更新pmt表。

  • i从1开始,因为pmt[0]已经确定为0。

  • 如果pattern[i] == pattern[len],说明当前字符可以扩展公共前后缀:

    • len++:公共前后缀长度+1。

    • pmt[i] = len:记录当前位置的最长公共前后缀长度。

    • i++:移动到下一个字符。


  else {if (len != 0) {len = pmt[len - 1];  // 回退到前一个字符的PMT值} else {pmt[i] = 0;i++;}}}return pmt;
}
  • 功能:当字符不匹配时,回退len

  • 如果len != 0,回退到pmt[len - 1](利用已计算的PMT值避免重复比较)。

  • 如果len == 0,说明无法回退,pmt[i] = 0,并移动到下一个字符i++


2. kmp方法 - 实现KMP搜索

public int kmp(String S, String T) {if (S == null || S.isEmpty() || T == null || T.isEmpty()) {return 0;}
  • 功能:检查输入参数是否有效。如果模式串S或文本串T为空,直接返回0。


  int[] pmt = BuildPMT(S);int count = 0;int j = 0;  // 模式串S的指针int i = 0;  // 文本串T的指针
  • 功能:初始化变量。

  • pmt:构建模式串S的部分匹配表。

  • count:记录ST中出现的次数。

  • j:指向模式串S的当前字符。

  • i:指向文本串T的当前字符。


   while (i < T.length()) {if (T.charAt(i) == S.charAt(j)) {i++;j++;if (j == S.length()) {count++;j = pmt[j - 1];  // 匹配成功后回退}}
  • 功能:字符匹配时的处理。

  • 如果T[i] == S[j],则同时移动ij

  • 如果j == S.length(),说明找到一个完整匹配:

    • count++:增加匹配计数。

    • j = pmt[j - 1]:回退j以继续搜索可能的其他匹配(避免遗漏重叠匹配)。


 else {if (j != 0) {j = pmt[j - 1];  // 利用PMT回退j} else {i++;  // 无法回退,移动i}}}return count;
}
  • 功能:字符不匹配时的处理。

  • 如果j != 0,回退jpmt[j - 1](利用PMT跳过不必要的比较)。

  • 如果j == 0,无法回退,只能移动i


关键点总结

  1. PMT表

    • pmt[i]表示模式串S[0..i]的最长公共前后缀长度。

    • 用于在匹配失败时快速回退j

  2. KMP搜索

    • 通过pmt表避免回溯i,保证i始终单向移动。

    • 时间复杂度:O(n + m)n为文本串长度,m为模式串长度)。

  3. 回退逻辑

    • 匹配失败时,j回退到pmt[j - 1]

    • 完整匹配后,j回退到pmt[j - 1]以继续搜索。

这个实现高效且正确,能够处理所有边界情况(如空串、无匹配、多次匹配等)。

相关文章:

  • 如何彻底卸载Android Studio?
  • 深度解析 LangChain、ReAct、ReROO 架构及其在 AI Agent 中的应用
  • node.js 实战——(Http 知识点学习)
  • EasyRTC音视频实时通话在线教育解决方案:打造沉浸式互动教学新体验
  • Oracle 11g RAC手动打补丁详细步骤
  • 240424 leetcode exercises II
  • 算法训练营第二天| 209.长度最小的子数组、59.螺旋矩阵II、区间和
  • Flink 消费 Kafka 数据流的最佳实践
  • 【激光雷达3D(7)】CenterPoint两阶段细化仅使用BEV特征;PV-RCNN两阶段细化使用体素特征;M3DETRTransformer统一多表征特征
  • 机器学习(7)——K均值聚类
  • 17.第二阶段x64游戏实战-人工遍历二叉树结构
  • 精益数据分析(20/126):解析经典数据分析框架,助力创业增长
  • Ollama工具调用(Tool Calls)业务应用案例
  • 各种各样的bug合集
  • 第一章:Model Context Protocol (MCP)
  • 【k8s】k8s是怎么实现自动扩缩的
  • 32BIT的SPI主机控制
  • 面试篇:Spring Boot
  • HOJ.单词统计
  • NLP实战(4):使用PyTorch构建LSTM模型预测糖尿病
  • 广西北海市人大常委会副主任李安洪已兼任合浦县委书记
  • 神舟二十号载人飞船发射升空
  • 新东方:2025财年前三季度净利增29%,第四财季海外业务将承压
  • 广东江门公布“小客车坠海致3死”事故评估报告,司机被判三年缓五年
  • 教培机构向学员提供盗版教材,法院:应承担著作权侵权责任
  • AI时代的阅读——当今时代呼唤文学的思想实验和人文认知