KMP算法

原理

next 数组存放的是当前长度下的 最长相同前后缀 的长度

next数组的应用

  • 当C和F不匹配时,怎么回退呢?答案是找到上一个

    因为上一个肯定是已经匹配完成的字母,我们找到它对应的 next 数组值来指导我们进行下一步操作

 

那么问题来了,现在 next 数组值 2代表什么呢?它想让我们干什么呢?

那么问题来了,现在 next 数组值 2代表什么呢?它想让我们干什么呢?

那么问题来了,现在 next 数组值 2代表什么呢?它想让我们干什么呢?

2表示当前已经匹配的子字符串 abcab的最长相同前后缀长度是 2,而我们数组下标是从 0️⃣开始的,如果我们按照 2的指示,正好可以跳转到下标 2 的位置(也就是字母C),开始下一次匹配。

前缀的应用场景是匹配串;
而后缀的应用场景是原字符串;
!!!!next 数组记录了我们的最长相同前后缀,在这里派上用场!!!!

​ 我们也就确定了 C 前面的字母已经匹配,可以放心的匹配之后的字母了

求next数组 

 for (int right = 1, left = 0; right < needleLength; right++) {
//            定义好两个指针right与left
//            在for循环中初始化指针right为1,left=0,开始计算next数组,right始终在left指针的后面
            while (left > 0 && needle.charAt(left) != needle.charAt(right)) {
//                如果不相等就让left指针回退,到0时就停止回退
                left = next[left - 1];//进行回退操作;
            }
            if (needle.charAt(left) == needle.charAt(right)) {
                left++;
            }
            next[right] = left;
// 这是从 1 开始的

        }
// 循环结束的时候,next数组就已经计算完毕了

KMP算法实现

    class Solution {
    public int strStr(String haystack, String needle) {
//自己敲一下子 前缀表不需要减一的实现方式
        int needleLength = needle.length();
        if (needleLength == 0) return 0;
//        当needle是空字符串时,返回0

        int[] next = new int[needleLength];
//        定义好next数组
        for (int right = 1, left = 0; right < needleLength; right++) {
//            定义好两个指针right与left
//            在for循环中初始化指针right为1,left=0,开始计算next数组,right始终在left指针的后面
            while (left > 0 && needle.charAt(left) != needle.charAt(right)) {
//                如果不相等就让left指针回退,到0时就停止回退
                left = next[left - 1];//进行回退操作;
            }
            if (needle.charAt(left) == needle.charAt(right)) {
                left++;
            }
            next[right] = left;
// 这是从 1 开始的

        }
// 循环结束的时候,next数组就已经计算完毕了


        for (int i = 0,j=0; i <haystack.length() ; i++) {

            while (j>0&&haystack.charAt(i)!=needle.charAt(j)){
                j=next[j-1];
            }
            if (haystack.charAt(i)==needle.charAt(j)){
                j++;
            }
            if (j==needleLength) return i-needleLength+1;
        }
        return -1;


    }
}

 next数组回溯详解

为什么要根据left = next[left - 1]回退?

这时候我们的 left 指针应该怎么办呢?

left = next[left - 1];

最长前缀和最长后缀是最长相同前后缀,见图右半部分。

这时候,最长前缀变成 ab最长后缀因为要和最长前缀保持一致,也缩水成了 ab

接着将 left 指针指向的 e 和 right 指针指向的 e 进行对比,发现相等。

就更新了当前数组的 next 数组

个人认为写的最好的KMP算法图解:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/solutions/1119642/duo-tu-yu-jing-xiang-jie-kmp-suan-fa-by-w3c9c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值