KMP的理解

来源:互联网 发布:西门子plc数据用于联网 编辑:程序博客网 时间:2024/05/19 18:42

KMP算法对串进行预处理,根据子串得出数组next,


不同与brute-force算法的是,当某位匹配失败时
1,主串不再回头进行匹配,仍从匹配失败的一位继续匹配,即 S[i] 与 T[j] 匹配失败时,i 不变化。(brute-force算法中 i = i - j)

2,子串不再回到首位进行匹配,而从 j = next[j] 进行下一次匹配。(brute-force中 j = 0)


下面,我们来分析一下next数组

int getNext(string target, int next[]){int n = target.size();int i = 0, j = 1;next[0] = -1;while (i < n){if (j == -1 || target[j] == target[i]){++j;++i;                        next[i] = j;}elsej = next[j];}}

next数组的意义在于: 子串 target[next[j]] 与 target[j] 拥有共同的前缀,这个前缀的长度不限定,只判断是否有共同前缀。

下面用 Kp 表示 子串 target[p] 的前缀(不包括target[p])

当 target[j] 等于 target[i] 时, K(j+1) = K(i+1),因此 next[i+1] = j + 1,

当target[j] 不等于 target[i] 时,默认 K(j -1) = K(i - 1),则 j 回溯 到 next[j] , next[j]  与 j 有相同 前缀, 因此与 i 也有相同 前缀,再次比较 target[next[j]] 于 target[i]

当 j 不断回溯,直到j = 0 时 target[j] 与target[i] 仍然匹配失败,则j = -1 此时 K(j + 1) 为0,可看作target[i+1] 于 target[j+1]有0个相同前缀,   K(i+1) = K(j+1) = 0,则next[i+1] = j+1 = 0。


如图,  当 j = 3,abab 与 ab 有 共同前缀 ‘a’  (不包括target[j]) 共同前缀数为1,next[3] = 1

           当 j = 4, ababb 与 abb 有共同前缀 ‘ab’ 因此 next[4] = 2




下面是利用 next 数组 进行字符串匹配

int strStr(string source, string target){const int sLen = source.size();const int tLen = target.size();int next[tLen];getNext(target, next);int i = 0, j = 0;while (i < sLen && j < tLen){if (source[i] == target[j]){++i;++j;}elsej = next[j];if (j == tLen)  //match successreturn i - j;}return -1;         // match fail}


以上是KMP匹配算法,正如前文所说

当 S[i] 与 T[j] 匹配失败时,j = next[j] ,即在子串中寻找一个 与 T[j] 有相同前缀 的 T[next[j]],则它与 S[i] 也有相同前缀(可能是0个),因此 i  匹配失败时不需要进行偏移,




next数组的优化:


int getNext(string target, int next[]){int n = target.size();int i = 0, j = 1;next[0] = -1;while (i < n){if (j == -1 || target[j] == target[i]){             ++j;             ++i;                  if (target[j] == target[i])                         next[i] = next[j];                     else                        next[i] = j;                }                elsej = next[j];        }}

改进部分 在于 增加判断 target[j+1] 和 target[i+1]

当 target[i + 1] == target[j + 1] && K(i + 1) == K(j + 1) 的时候

如果 主串与子串的 target[i+1] 匹配失败,则主串与target[j + 1] 一定也不同,没必要进行比较,

则 子串 的下一个匹配的位置 向前回溯,直到与 target[i+1] 有相同的前缀,并且不等于target[i+1]

0 0
原创粉丝点击