状态j的含义是已经匹配的长度,pattern[j] 是pattern中下一个待匹配的字符
需要计算一个状态转移表:
在状态j, 对于字符pattern[j],状态转移自然是 j = j + 1,这是match case
对于其他字符,是unmatch case, 状态转移是相当于把pattern[1: j - 1]放到状态机里运行得到的状态再以pattern[j]作为转移。
重点:状态机是部分可用的。在计算状态j的转移的时候,状态0到 j - 1的转移都已经算出来了,而pattern[1:j-1]总共只有j - 1个字符,产生的状态值肯定是小于等于j - 1,此时部分的状态机也是够用的。
维护一个状态X,代表把pattern[1: j - 1]序列输入到状态机里运行的结果,计算完 j 的转移, x对pattern[j]进行一次跳转进行更新
class KMP {
public static int R = 256;
private int[][] dfa;
private int M;
public KMP(String pattern) {
M = pattern.length();
dfa = new int[M][R];
dfa[0][pattern.charAt(0)] = 1;
for (int x = 0, i = 1; i < M; ++i) {
for (char c = 0; c < R; ++c) {
dfa[i][c] = dfa[x][c];
}
dfa[i][pattern.charAt(i)] = i + 1;
x = dfa[x][pattern.charAt(i)];
}
}
public int match(String text) {
for (int i = 0, j = 0; j < text.length(); ++j) {
i = dfa[i][text.charAt(j)];
if (i == M) return j - M + 1;
}
return -1;
}
}