The construction walks i from 1 to m − 1 holding k, the length of the current border. If p[i] equals p[k] the border extends and k rises by 1. If not, k falls to fail[k] and the test is repeated — that repetition is the inner loop, and it is the only part of the algorithm whose cost is not one per character.
Theorem · The inner loop runs at most m − 1 times in totalOver the whole construction of fail[] for a pattern of length m, the number of inner-loop iterations is at most m − 1, so the total work is at most 2m − 1 operations and the construction is O(m).
Take k as a potential. It starts at 0 and is never negative, because the inner loop stops at 0 and fail[j] ≥ 0 for every j.
The outer loop runs m − 1 times and each iteration increases k by at most 1, so the total increase over the whole construction is at most m − 1.
Every inner-loop iteration sets k to fail[k], which is strictly less than k because a border of p[0..k−1] is shorter than it. So each inner iteration decreases the potential by at least 1. Since the total decrease cannot exceed the total increase plus the starting value, the number of inner iterations is at most m − 1.
□
The panel prints that total under the name inner-loop iterations and the bound beside it as 2m. The bound it prints is the looser 2m rather than m − 1 because it is counting the outer comparison as well, and because 2m is the form the claim is usually quoted in.
Example · Seven prefixes of aabaaab, and where the chain is followedThe pattern is aabaaab and fail[1..7] comes out 0, 1, 0, 1, 2, 2, 3. The inner loop fires at exactly two places: at the b in position 3, where the border of length 1 cannot be extended and falls to 0, and at position 6, where the border of length 2 cannot be extended by an a and falls to 1 — from which the a does extend it back to 2. One iteration each, two in total, against a bound of 14.
The same count on the other patterns the kit ships
pattern m fail[1..m] inner bound 2m
ababaca 7 0 0 1 2 3 0 1 2 14
aaaaa 5 0 1 2 3 4 0 10
abcabcabd 9 0 0 0 1 2 3 4 5 0 2 18
aabaaab 7 0 1 0 1 2 2 3 2 14
abcdefg 7 0 0 0 0 0 0 0 0 14
Two of the five never enter the inner loop at all. aaaaa never needs to, because every character extends the border; abcdefg never needs to, because k is 0 at every step and the loop's guard is k > 0. The three that do enter it enter it twice, and on ababaca and abcabcabd those two iterations both happen at a single character, while on aabaaab they are one at each of two characters.
That distinction is worth holding on to, because it is where an amortised argument earns its keep. A pattern whose chain is followed twice at one character has a step the per-character reasoning cannot bound; a pattern whose chain is followed once at each of two characters does not. Both have the same total, and the total is what the theorem is about.
The construction is not the matching, and both are counted
The failure function costs O(m) and the search over the text costs O(n), and the panel keeps them in separate counters because they are separate claims with separate proofs. On the text aabaaabaaabaabaaab, 18 characters, the search makes 19 comparisons against a bound of 2n = 36 and finds 3 occurrences at offsets 0, 4 and 11. The naive matcher makes 42 on the same input.
So the full accounting for KMP on this input is 2 inner iterations plus the 6 outer comparisons to build the array, and then 19 comparisons to search: under 30 operations where naive matching spends 42 comparisons alone. The preprocessing is cheap here, and on a long text it is negligible — which is the practical reason the failure function is built at all rather than the theoretical one.
Why the search bound is 2n and not n
The search loop has the same shape as the construction: one comparison per text character, plus a fallback loop that lowers k. The same potential argument applies with k rising at most once per text character, so the fallbacks total at most n and the whole search is at most 2n. The factor of two is the fallbacks, and it is the price of never moving the text pointer backwards.
On this text the measured 19 is just over n, so almost all of those comparisons advanced the text pointer and hardly any were fallbacks. On the adversarial input from the previous module KMP made 44 comparisons on 24 characters, which is close to 2n and is the shape the bound was written for.