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

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;
}

Algorithm 2

Lemma

Let , then

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;
}