返回

程序员谈KMP:揭秘K = next[K]的来龙去脉

Android

K = next[K]:揭示 KMP 算法中的关键优化

什么是 KMP 算法?

在字符串匹配领域,KMP 算法以其效率著称。它可以在 O(n+m) 时间内查找主串中是否存在子串,其中 n 是主串长度,m 是子串长度。KMP 算法的核心思想是利用 next 数组进行失配处理,避免了朴素算法中重复回溯的繁琐步骤。

next 数组:子串中公共前缀的秘诀

next 数组是长度与子串相同的整数数组,它记录了子串的前 k 个字符与所有前缀(自身除外)的最长公共前缀的长度。也就是说,next[k] 表示子串的前 k 个字符与前 k-1 个字符的最长公共前缀的长度。

K = next[K]:揭示本质

许多文章在介绍 KMP 算法时往往忽略了一个重要结论:K = next[K]。这个结论揭示了 next 数组的本质,并为失配处理过程带来了至关重要的优化。

如何得出 K = next[K]?

next 数组的计算通常采用递推的方式,从 next[1] 开始逐个计算。在计算 next[k] 时,我们先将它初始化为 0,然后从 next[k-1] 开始,逐个比较子串的前 k-1 个字符与前 k-2 个字符的最长公共前缀长度。如果有公共前缀,则更新 next[k] 为公共前缀长度;否则,保持为 0。

当我们计算到 K = next[K] 时,意味着子串的前 K 个字符与前 K-1 个字符完全相同。在这种情况下,再继续计算 next[K+1] 已无意义,因为 next[K+1] 只可能是 0。

因此,我们可以得出结论:K = next[K]。

K = next[K]:优化失配处理

K = next[K] 不仅简化了 next 数组的计算过程,还为失配处理过程提供了重要优化。

当 KMP 算法在匹配过程中遇到不匹配时,它会回溯到主串的当前位置减去 next[K] 的位置继续匹配。之所以如此,是因为如果子串的前 K 个字符与主串的前 K 个字符完全相同,那么前 K-1 个字符也一定相同。因此,我们可以直接从当前位置减去 next[K] 继续匹配,而无需回溯到开头。

利用 K = next[K] 优化代码示例

def kmp_match(pattern, text):
    """
    KMP 算法实现字符串匹配

    Args:
        pattern (str): 模式串
        text (str): 主串

    Returns:
        list[int]: 匹配到的位置索引
    """

    # 构建 next 数组
    next = build_next(pattern)

    # 初始化匹配索引
    i, j = 0, 0

    # 匹配过程
    matches = []
    while i < len(text):
        if pattern[j] == text[i]:
            i += 1
            j += 1
            if j == len(pattern):
                matches.append(i - j)
                j = next[j]  # 利用 KMP 优化回溯
        else:
            if j != 0:
                j = next[j]  # 利用 KMP 优化回溯
            else:
                i += 1

    return matches


def build_next(pattern):
    """
    构建 next 数组

    Args:
        pattern (str): 模式串

    Returns:
        list[int]: next 数组
    """

    next = [0] * len(pattern)
    i, j = 0, 1
    while i < len(pattern) and j < len(pattern):
        if pattern[i] == pattern[j]:
            next[j] = i + 1
            i += 1
            j += 1
        else:
            if i != 0:
                i = next[i - 1]
            else:
                j += 1
    return next

总结

K = next[K] 是 KMP 算法中一个至关重要的结论,它揭示了 next 数组的本质,并为失配处理过程提供了重要的优化依据。理解这个结论对于深入理解 KMP 算法的运作机制至关重要。

常见问题解答

  1. 为什么 K = next[K] 是 KMP 算法的关键?

答:因为这个结论揭示了 next 数组的本质,并为失配处理过程提供了重要的优化依据,极大地提高了算法的效率。

  1. KMP 算法是如何利用 K = next[K] 优化失配处理的?

答:当遇到不匹配时,KMP 算法利用 next[K] 优化回溯,直接从当前位置减去 next[K] 继续匹配,避免了朴素算法中的重复回溯。

  1. next 数组的构建过程是怎样的?

答:next 数组通常采用递推的方式构建,从 next[1] 开始,逐个计算每个元素,通过比较子串的前 k 个字符与前 k-1 个字符的最长公共前缀长度来更新。

  1. 在 KMP 算法中,如何利用 next 数组进行失配处理?

答:当遇到不匹配时,如果 j 不为 0,则将 j 更新为 next[j];否则,将 i 更新为 next[i - 1]。这种优化回溯的方式避免了重复的回溯步骤。

  1. K = next[K] 的结论与 KMP 算法的效率提升有何关系?

答:K = next[K] 的结论揭示了 next 数组的规律性,从而简化了 next 数组的计算过程,并为失配处理过程提供了优化依据,极大地提高了算法的效率。