The Knuth-Morris-Pratt Algorithm is an algorithm that computes for a string of length in time and space, where
Algorithm 0
Applying the definition to find yields an algorithm that solves the problem in time and space.
std::vector<int> knuth_morris_pratt(int n, const std::string &s) {
std::vector pi(n + 1, 0);
for (int i = 2; i <= n; i++) {
for (int j = i - 1; j > 0; j--) {
if (s.substr(0, j) == s.substr(i - j, j)) {
pi[i] = j;
break;
}
}
}
return pi;
}Algorithm 1
Lemma
Proof
Based on Algorithm 0, applying the lemma to get an upper bound for yields an algorithm that solves the problem in time and space.
std::vector<int> knuth_morris_pratt(int n, const std::string &s) {
std::vector pi(n + 1, 0);
for (int i = 2; i <= n; i++) {
for (int j = pi[i - 1] + 1; j > 0; j--) {
if (s.substr(0, j) == s.substr(i - j, j)) {
pi[i] = j;
break;
}
}
}
return pi;
}Proof
The total number of executions of
s.substr(0, j) == s.substr(i - j, j)is
Algorithm 2
Lemma
Let , then
Proof
Let , and let denote the -th largest element in .
Then, for each in , since
it follows that
Based on Algorithm 1, applying the lemma to rule out some impossible yields an algorithm that solves the problem in time and space.
std::vector<int> knuth_morris_pratt(int n, const std::string &s) {
std::vector<int> pi(n + 1);
pi[0] = pi[1] = 0;
for (int i = 1, j = 0; i < n; i++) {
while (j && s[j] != s[i]) {
j = pi[j];
}
j += s[j] == s[i];
pi[i + 1] = j;
}
return pi;
}