z[i]记录了从第i位置开始,与原串的最长公共前缀。
L记录最远前缀匹配的起点,R记录最远前缀匹配的终点。
如果当前位置在R之内,那么i的匹配情况,等于i-L+1的匹配情况。这是因为1对应L,2对应L+1。。。i-L+1对应i。
当然,如果字符串起点是0,那么对应的是i-L。
如果该处的匹配长度z[i-L+1]+i不超出R,那么就是结果;如果超过了,由于R开外的匹配信息并没处理过,那么z[i-L+1]不能完全使用,只能匹配到R。
如果通过前述信息匹配到R,对于R开外的直接暴力匹配即可。
暴力匹配后R会增加,增加次数不超过字符串长度,所以保证了复杂度。
每次匹配完后,如果前缀涉及的位置超出了R,修改对应的L和R。
int exkmp(char *s, int n, char *t, int m) {t[m] = '#';copy(s, s + n, t + m + 1);z[0] = m;int L = 0, R = -1, ret = 0;for (int i = 1; i <= n + m; i++) {if (i <= R)z[i] = min(z[i - L], R - i + 1);elsez[i] = 0;while (i + z[i] <= n + m && t[i + z[i]] == t[z[i]]) ++z[i];if (i + z[i] - 1 > R) L = i, R = i + z[i] - 1;if (z[i] == m) ret++;}return ret;
}
