vector<int> getNext(const string& p){ int n = p.size(); vector<int> next(n); next[0] = -1; int i = 0, j = -1; // !!! i < n 则会在下面越界,因为0已经求过了,循环只会进行n-1次 while (i < n - 1) { if (j == -1 || p[i] == p[j]) { ++i, ++j; next[i] = j; } else { j = next[j]; } } return next; }
intKMP(const string& t, const string& p){ vector<int> next = getNext(p); int n = t.size(), m = p.size(); int i = 0, j = 0; // !!! j可以为负数,和无符号比较会转换为无符号比较法(南辕北辙) while (i < n && j < m) { if (j == -1 || t[i] == p[j]) { ++i; ++j; } else { j = next[j]; } } if (j == p.size()) return i - j; else return-1; }
KMP之Next优化
比如[ A B A B ]这个串,按照上面所述KMP得到的结果是[-1, 0, 0, 1],然而,例如匹配的是[ A B A B D E],在下标为3处失败了,next指导去下标1处继续匹配,但是,下标1和下标3都是B,没有必要再进行比较了。诸如此类的例子还有[ A A A A B],用上述KMP得到的next是[-1, 0, 1, 2, 3]
方法就是在 ++i, ++j 后加一步判断,本来直接 next[i]=j 但是如果 p[i]==p[j] 则如果以后匹配 p[i] 失败,则匹配 p[j] 肯定也失败啊,所以如果两者相等,直接 next[i] = next[j] 。此时的结果对于[ A B A B ]产生的是[-1, 0, -1, 0];对于[ A A A A B]产生的是[-1, -1, -1, -1, 3]
vector<int> getNext(const string& p){ int n = p.size(); vector<int> next(n); next[0] = -1; int i = 0, j = -1; while (i < n - 1) { if (j == -1 || p[i] == p[j]) { ++i, ++j; if (p[i] == p[j]) // new next[i] = next[j]; // new else// new next[i] = j; } else { j = next[j]; } } return next; }
intKMP(const string& t, const string& p){ vector<int> next = getNext(p); int n = t.size(), m = p.size(); int i = 0, j = 0; while (i < n && j < m) { if (j == -1 || t[i] == p[j]) { ++i; ++j; } else { j = next[j]; } } if (j == p.size()) return i - j; else return-1; }