AI 刷题的优势之处 | KMP算法 | 豆包MarsCode AI刷题

119 阅读5分钟

我在刷题过程中遇到了需要使用KMP算法的题目,但我对这个算法一知半懂,这个时候MARSCODE AI的优势就体现出来了,帮助我清晰理解了这一算法!

首先,可以让MARSCODE AI介绍一下KMP算法:

KMP算法(Knuth-Morris-Pratt算法)是一种用于在一个字符串中查找一个子串的高效算法。它通过预先计算一个辅助数组(也称为前缀函数或失效函数)来避免在匹配过程中不必要的回溯,从而提高了匹配的效率。

KMP算法的核心思想是,当在主串中匹配到某个字符与模式串中的字符不匹配时,它能够利用已经匹配的部分信息,跳过一些不必要的比较,从而快速地找到下一个可能的匹配位置。

以下是KMP算法的详细步骤:

  1. 构建前缀函数:对于模式串中的每个位置,计算出一个前缀函数值。这个值表示在当前位置之前的子串中,最长的相同前缀和后缀的长度。例如,对于模式串 "ABABCABAB",前缀函数值为 [0, 0, 1, 2, 0, 1, 2, 3, 2]。
  2. 匹配过程:使用模式串的前缀函数来指导匹配过程。从主串的第一个字符开始,逐个与模式串中的字符进行比较。如果匹配成功,则继续比较下一个字符;如果匹配失败,则根据前缀函数的值,将模式串向后移动相应的位数,然后继续比较。
  3. 避免回溯:通过前缀函数,KMP算法可以避免在匹配失败时进行不必要的回溯。例如,如果在主串的某个位置匹配失败,前缀函数会告诉我们应该将模式串向后移动多少位,以便继续匹配。

KMP算法的时间复杂度为O(m+n),其中m和n分别是主串和模式串的长度。这是因为在最坏情况下,每个字符只需要比较一次,而构建前缀函数的时间复杂度也是线性的。

按照这个思想,我们可以写出next数组代码

其中,next[i]表示包含第i个元素的最长前缀长度:

x=input()
n=len(x)
nx=[0]*(n+1)
i=1
j=0
while i<n:
    while(j>0 and x[j]!=x[i]):
        j=nx[j-1]
    if(x[j]==x[i]):
        j+=1
    nx[i]=j
    i+=1
nx=[0]+nx

可以使用MARSCODE AI对其进行详细解读:

  1. x=input():从标准输入读取一个字符串,并将其赋值给变量 x
  2. n=len(x):获取字符串 x 的长度,并将其赋值给变量 n
  3. nx=[0]*(n+1):创建一个长度为 n+1 的列表 nx,并初始化为全零。这个列表将用于存储前缀函数的值。
  4. i=1 和 j=0:初始化两个变量 i 和 j,分别用于遍历字符串 x 和跟踪当前匹配的前缀长度。
  5. while i<n::开始一个循环,遍历字符串 x 的每个字符。
  6. while(j>0 and x[j]!=x[i])::当 j 大于零且当前字符 x[j] 不等于 x[i] 时,执行循环。这个循环用于回溯 j,找到最长的匹配前缀。
  7. j=nx[j-1]:如果当前字符不匹配,将 j 更新为 nx[j-1],即前一个字符的前缀函数值。这是 KMP 算法的关键步骤,用于避免不必要的比较。
  8. if(x[j]==x[i])::如果当前字符匹配,执行条件块。
  9. j+=1:如果当前字符匹配,增加 j 的值,表示匹配的前缀长度增加了一个字符。
  10. nx[i]=j:将当前匹配的前缀长度 j 存储在 nx[i] 中。
  11. i+=1:继续遍历字符串的下一个字符。
  12. nx=[0]+nx:在循环结束后,将 nx 列表的第一个元素设置为零,并将其与原列表拼接,得到最终的前缀函数列表。

虽然KMP算法代码看起来简短,但是它的思想非常精妙。

MARSCODE AI 介绍其具有以下优势:

  1. 高效性:KMP算法的时间复杂度为O(m+n),其中m和n分别是主串和模式串的长度。这是因为在最坏情况下,每个字符只需要比较一次,而构建前缀函数的时间复杂度也是线性的。
  2. 避免回溯:通过前缀函数,KMP算法可以避免在匹配失败时进行不必要的回溯。例如,如果在主串的某个位置匹配失败,前缀函数会告诉我们应该将模式串向后移动多少位,以便继续匹配。
  3. 预处理时间短:构建前缀函数的时间复杂度为O(n),其中n是模式串的长度。这意味着即使对于很长的模式串,预处理时间也相对较短。
  4. 适用性广:KMP算法可以用于任何类型的字符集,包括ASCII字符、Unicode字符等。
  5. 易于实现:KMP算法的实现相对简单,只需要对模式串进行一次预处理,然后就可以在主串中进行匹配。
  6. 优化动态规划:在某些情况下,KMP算法可以用于优化动态规划问题,例如在计算字符串的最小操作次数时,可以利用KMP算法的前缀函数来减少计算量。