结合 Leetcode 题探究KMP算法

一、题目

找出字符串中第一个匹配项的下标

二、思路

2.1 KMP的核心思想

  • 与普通的双层暴力遍历相比,KMP算法的精髓在于利用已匹配的前缀信息来优化搜索过程 。当发生不匹配时,算法不是简单地将模式串后移一位重新开始,而是根据预先计算的next数组,直接将模式串滑动到下一个可能匹配的位置。

2.2 next数组的实质

next[i] 表示在模式串的前 i 个字符组成的子串中,最长的相等真前缀与真后缀的长度。

  • 真前缀:不包含最后一个字符的前缀

  • 真后缀:不包含第一个字符的后缀

  • 核心价值 :当字符匹配失败时,next[i] 告诉我们模式串应该回溯到什么位置继续匹配

2.3 基础递推关系

next[i] 的计算基于 next[i-1] 和当前字符 pattern[i]

  1. 已知条件 :若 next[i-1] = lastNextLen,表明子串 pattern[0...lastNextLen-1] 中,前 lastNextLen 个字符与后 lastNextLen 个字符完全相等

    复制代码
    pattern[0...lastNextLen-1] == pattern[i-lastNextLen...i-1]
  2. 关键比较 :为了高效计算,利用上述 next[i-1]中已经包含的信息,比较 pattern[lastNextLen]pattern[i],就可以得到next[i]

(1) 如果相等next[i] = lastNextLen + 1(相等前后缀长度增加1)

(2) 如果不相等 :回溯到 next[lastNextLen] 继续尝试匹配

三、代码

java 复制代码
class Solution {
    public int strStr(String haystack, String needle) {
        // 使用KMP算法

        // 1、得到 next 数组
        int[] next = getNextArray(needle);

        // 2、借助 next 数组完成遍历
        int i = 0;  // 母串指针
        int j = 0;  // 子串指针
        int m = haystack.length();
        int n = needle.length();
        while(i < m && j < n){
            if(j == -1 || haystack.charAt(i) == needle.charAt(j)){
                i++;
                j++;
            }else{
                j = next[j];
            }
        }

        return j == n ? i - n : -1; // 判断子串的指针是否已经遍历完成
    }

    private int[] getNextArray(String s){
        // next数组其实是不包含当前字符的使得真前缀与真后缀相同的最大长度
        // 也就是 next[i] 要借助 next[i-1] 和 s.charAt(i) 来得到
        // 若 next[i-1] = lastNextLen 可知,s 的 [0, lastNextLen-1] 对应的字符串 == s 的 [i-1-lastNextLen, i-1]
        // 为最大地利用现有资源,所以先判断 s.charAt(lastNextLen) ?= s.charAt(i)
        // 若不等,则继续回溯进行判断
        int len = s.length();
        int[] next = new int[len];
        next[0] = -1;
        int lastNext = -1;       // 记录上一个next

        int i = 0;
        while(i < len - 1){
            // lastNext == -1:说明已经回溯到开头,没有公共前后缀,next[i+1] = 0
            // s[i] == s[lastNext]:当前字符匹配成功,最长公共前后缀长度+1
            if(lastNext == -1 || s.charAt(i) == s.charAt(lastNext)){  
                next[i + 1] = lastNext + 1;
                i++;
                lastNext++; 
            }else{  // 字符不匹配时,利用已计算的next信息进行回溯,找到更短的相同前后缀继续尝试匹配
                lastNext = next[lastNext];
            }
        }  

        return next;
    }
}
相关推荐
烬羽18 分钟前
递归老写崩?一个"退回"公式,把回溯题变成填空题
javascript·深度学习·算法
闪电悠米28 分钟前
力扣hot100-41.缺失的第一个正数-原地哈希详解
数据结构·算法·哈希算法
星空露珠1 小时前
28种颜色对应名称,
开发语言·数据库·算法·游戏·lua
QXWZ_IA3 小时前
桥梁数字孪生怎么落地?
人工智能·科技·算法·智能硬件·政务
Kel3 小时前
输出层与反分词(Output Layer & Detokenization)
人工智能·算法·架构
陕西企来客3 小时前
2026年7月技术好GEO优化方案:算法适配与内容策略
人工智能·算法·机器学习·技术好geo优化
风栖柳白杨3 小时前
【面试】AI算法工程师_空白自测版本
人工智能·算法·面试
闪电悠米5 小时前
力扣hot100-73.矩阵置零-标记数组详解
算法·leetcode·矩阵
栋***t5 小时前
从“纸质试卷”到“AI智能组卷”,麦塔在线考试系统如何重构出题逻辑?
java·大数据·人工智能·算法·重构
wabs6665 小时前
关于图论【卡码网100.最大岛屿的面积的思考】
数据结构·算法·图论