kmp算法快速简易理解

1.求next数组

1.1 定义

  • 什么是最长相等前后缀长度

​ 字符串 ab 的最长相等前后缀为空集,长度为0

​ 字符串 aba 的最长相等前后缀为a,长度为1

​ 字符串 aaa 的最长相等前后缀为aa,长度为2

​ 字符串 ababa 的最长相等前后缀为aba,长度为3

  • next数组是什么?

    next[i]:前i-1个字符的 最长相等前后缀长度 + 1

    str:   a  b  a  b  a
    next:  0  1  1  2  3
    

    next[3] = f("aba") + 1 = 1 + 1 = 2

    str:   (a  b  a)  b  a
    next:   0  1  1   ?  

1.2 next数组的两种情况

  1. 本质是自己和自己匹配
  2. 初始化:i = 1表示next数组位置/主串位置。j = 0表示子串位置。
  3. j相当于已匹配个数。

下面以ababaaab作为例子,计算next数组

初始位置

a b a b a a a b
  a b a b a a a b
  ↑
(i = 1; j = 0)

情况一:字符相同

0 1 1
a b a b a a a b
    a b a b a a a b
      ↑
(i = 3; j = 1)

则:

1. 先将结果记下来,对于当前位置,已经匹配了j=1个,即aba的部分的最长相等前后缀为1,根据next数组定义,则next[i]=j+1
2. i++; j++; 匹配下一位

结果:

0 1 1 2
a b a b a a a b
    a b a b a a a b
        ↑
(i = 4; j = 2)

情况二:字符不同

0 1 1 2 3
a b a b a a a b
    a b a b a a a b
          ↑
(i = 5; j = 3)

则:

1.先将结果记下来,这部分同情况一,next[i] = j + 1
2.循环判断,如果不匹配,j = next[i] - 1
  直到j == -1 或成功匹配 跳出循环
3. i++; j++; 匹配下一位

j = next[i] - 1 解析:

字符串在"abab"的"b"处失配,通过next[3]("b"的位置为3)我们得知,前面"aba"部分的最长相等前后缀为 next[3] - 1 = 1。所以接下来不需要重新开始匹配,可以从开头跳过1个字符。综上,即j = next[i] - 1。

跳出循环解析:

  1. 如果j一直到开头都没有匹配到,因为next[0] - 1 = 0 - 1 = -1 的原因,跳出循环后进行j++,下一次相当于重头匹配。
  2. 如果j匹配到了,此时相当于情况1。

代码

    public int[] getNext(String s)
    {
        int[] next = new int[s.length()];
        int i = 1;
        int j = 0;
        next[0] = 0; // 定义
        
        while (i < s.length()) {
            next[i] = j + 1; // 首先记录当前结果
            // 如果不匹配,则找到已匹配的个数(j),
            while (j >= 0 && s.charAt(i) != s.charAt(j)) {
                j = next[j] - 1;
            }
            // 二者指针右移,继续下一位匹配
            j++;
            i++;
        }
        return next;

    }

2. kmp算法

public int kmp(String str, String substr)
{
    // 从0开始匹配
    int i = 0;
    int j = 0;
    // 获取子串的next数组
    int[] next = getNext(substr);
   

    while (i < str.length() && j < substr.length()) {
        // 匹配下一位
        if (j == -1 || str.charAt(i) == substr.charAt(j)) {
            i++;
            j++;
        }
        else
            // 找到合适的位置(已匹配个数)
            j = next[j] - 1;
    }
	// 成功匹配,返回下标
    if (j == substr.length()) {
        return i - substr.length();
    }
    // 失败匹配
    return -1;
}
posted @   aminor  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
/**/ /**/
点击右上角即可分享
微信分享提示