简易KMP前缀表构建实现存在哪些问题?
你的KMP前缀表实现存在的核心问题
嘿,我来帮你拆解下这段前缀表实现的问题所在~
首先,先明确KMP前缀表(也叫部分匹配表)的核心:它要记录的是模式串中每个位置结尾的子串,与模式串前缀的最长相等前后缀长度。而你的实现里,当遇到字符不匹配时直接将i重置为0,这会丢失之前已经匹配到的前缀信息,导致无法正确计算出最长的相等前后缀,最终让KMP算法的回溯逻辑失效。
举个错误的实例
比如模式串"AAACAAAA",用你的代码计算前缀表时:
- 当处理到索引7(最后一个'A')时,此时
i的值是3(对应模式串中的'C'),当前字符'A'和'C'不匹配,你的代码直接把i置为0,然后比较'A'和模式串第一个字符'A'匹配,i变为1,最终T[7] = 1。
但实际上,这个位置的最长相等前后缀长度应该是3(前缀"AAA"和后缀"AAA"完全匹配),你的代码得到的结果明显错误。
问题的根源
你的实现只处理了匹配成功的情况,而在匹配失败时的回溯逻辑是错误的:正确的做法不是直接把i重置为0,而是应该让i回退到T[i-1]的位置,继续尝试匹配,直到i回到0或者找到匹配的字符为止。
修正后的前缀表实现
int[] computePrefixTable(String P) { int[] T = new int[P.length()]; int i = 0; // i表示当前最长相等前后缀的长度 for (int j = 1; j < P.length(); ++j) { // 匹配失败时,回退到之前的前缀位置 while (i > 0 && P.charAt(j) != P.charAt(i)) { i = T[i - 1]; } // 匹配成功,延长最长相等前后缀长度 if (P.charAt(j) == P.charAt(i)) { i++; } T[j] = i; } return T; }
修正逻辑的解释
- 当
P[j]和P[i]不匹配时,我们通过T[i-1]找到更短的可能相等的前后缀,而不是直接回到起点,这样就能保留之前已经匹配的有效信息,确保计算出的是最长的相等前后缀长度。 - 用
while循环而不是if,是因为回退后可能仍然不匹配,需要继续回退,直到i为0或者找到匹配的字符。
这样修正后的前缀表才能正确支撑KMP算法的高效匹配,避免不必要的字符比较。
内容的提问来源于stack exchange,提问作者devoured elysium
相关产品推荐
相关产品推荐

