首页 > 编程语言 >kmp算法快速简易理解

kmp算法快速简易理解

时间:2022-10-15 15:33:12浏览次数:55  
标签:int 后缀 匹配 substr ++ next 简易 算法 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;
}

标签:int,后缀,匹配,substr,++,next,简易,算法,kmp
From: https://www.cnblogs.com/aminor/p/16794291.html

相关文章