【蓝桥杯】KMP算法难以理解只能硬背?东哥这个思路让你10分钟彻底掌握

本文深入浅出地介绍了KMP算法,通过动态规划的思路,帮助读者理解如何构建状态转移图,避免重复扫描,提高字符串匹配效率。适合准备蓝桥杯、面试的程序员阅读。文章通过实例讲解,辅助以二维数组,让KMP算法不再难以理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

🍊 Java学习:Java从入门到精通总结

🍊 Spring系列推荐:Spring源码解析

📆 最近更新:2021年12月13日

🍊 个人简介:通信工程本硕💪、阿里新晋猿同学🌕。我的故事充满机遇、挑战与翻盘,欢迎关注作者来共饮一杯鸡汤

🍊 点赞 👍 收藏 ⭐留言 📝 都是我最大的动力!

KMP 算法(Knuth-Morris-Pratt 算法)是一个著名的字符串匹配算法,效率很高,说实话,有点复杂。

这种高级且常用的算法经常会在各种竞赛 / 面试场景中出现,先给大家说一个真实的例子吧,在我当初校招面试华为sp时,面试官就让我当场写一个KMP算法,大致的题目如下:
​​​​​​​​
在这里插入图片描述
这个算法是一个比较奇葩的存在,业内流行一句话,当你第一遍没学会掌握kmp时,之后再看就会耗费成倍的精力。不幸的是我第一遍没掌握这个算法,所以当时我是直接把模板给背诵了下来,以一种非正常的方式通过了面试。

之后复盘环节偶然看到了东哥(公众号labuladong)使用动态规划的思路给出的解析,顿感豁然开朗,把之前非常诡异的next数组定义给丢掉了,二维数组的解法不禁让我直呼内行,先整理如下,祝各位蓝桥杯顺利~



约定:pat表示模式串,长度为M,txt表示文本串,长度N为N。KMP 算法是在txt中查找子串pat,如果存在,返回这个子串的起始索引,否则返回 -1。

目前大部分的解析应该是:对pat进行一顿操作之后生成一个next数组,再利用next数组的数据去一顿操作来匹配txt。next数组和txt、pat的前缀后缀有关,很难理解,理解了可能也忘的比较快。我么可以用一个二维数组来减少代码长度,提高可解释性。

1 概述

普通字符串匹配可以用暴力破解来写,具体思路是:从txt起始索引0开始匹配pat,匹配上了则返回起始索引,匹配不上则再从txt索引1处开始匹配,以此类推…

在这里插入图片描述

KMP 算法的不同之处在于,它会花费空间来记录一些信息,在上述情况中就会显得很聪明。由于pat中根本不存在c字符,所以可以直接跳过这个字符:

在这里插入图片描述

KMP 算法则不会重复扫描txt,而是借助next数组中储存的信息把pat移到正确的位置继续匹配,用空间换时间。

传统的KMP算法框架如下:

// KMP算法主体逻辑。str是主串,pattern是模式串
public static int kmp(String str, String pattern) {
   
   
    //预处理,生成next数组
    int[] next = getNexts(pattern);
    int j = 0;
    //主循环,遍历主串字符
    for (int i = 0; i < str.length(); i++) {
   
   
        while (j > 0 && str.charAt(i) != pattern.charAt(j)) {
   
   
            //遇到坏字符时,查询next数组并改变模式串的起点
            j = next[j];
        }
        if (str.charAt(i) == pattern.charAt(j)) {
   
   
            j++;
        }
        if (j == pattern.length()) {
   
   
            //匹配成功,返回下标
            return i - pattern.length() + 1;
        }
    }
    return -1;
}
// 生成Next数组
private static int[] getNexts(String pattern) {
   
   
    int[] next = new int[pattern.length()];
    int j = 0;
    for (int i=2; i<pattern.length(); i++) {
   
   
        while (j != 0 && pattern.charAt(j) != pattern.charAt(i-1)) {
   
   
            //从next[i+1]的求解回溯到 next[j]
            j = next[j];
     
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小王曾是少年

如果对你有帮助,欢迎支持我

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值