http://www.mathcs.emory.edu/~cheung/Courses/323/Syllabus/Text/Matching-KMP1.html
http://www.mathcs.emory.edu/~cheung/Courses/323/Syllabus/Text/Matching-KMP2.html
http://www.mathcs.emory.edu/~cheung/Courses/323/Syllabus/Text/Matching-KMP3.html
Suppose the red character in the input text is the first unmatched character:
Maximum overlap of a prefix:
"Partial match" table (also known as "failure function")
We want to be able to look up, for each position in W, the length of the longest possible initial segment ofW leading up to (but not including) that position, other than the full segment starting at W[0] that just failed to match; this is how far we have to backtrack in finding the next match. Hence T[i] is exactly the length of the longest possible proper initial segment of W which is also a segment of the substring ending at W[i - 1]. We use the convention that the empty string has length 0. Since a mismatch at the very start of the pattern is a special case (there is no possibility of backtracking), we set T[0] = -1
Failure Function
public int[] prekmp(String pattern) {
int[] next = new int[pattern.length()];
next[0] = -1;
next[1] = 0;
int pos = 2, cnd = 0;
while (pos < pattern.length()) {
if (pattern.charAt(pos - 1) == pattern.charAt(cnd)) {
cnd++;
next[pos] = cnd;
} else {
cnd = next[cnd];
while (cnd > 0
&& pattern.charAt(pos - 1) != pattern.charAt(cnd))
cnd = next[cnd];
if (cnd < 0) {
next[pos] = 0;
cnd = 0;
} else {
next[pos] = cnd;
}
}
pos++;
}
return next;
}
public int[] prekmpOpt(String pattern) {
int[] next = new int[pattern.length()];
int i = 0, j = -1;
next[0] = -1;
while (i < pattern.length() - 1) {
while (j >= 0 && pattern.charAt(i) != pattern.charAt(j))
j = next[j];
i++;
j++;
next[i] = j;
}
return next;
}
KMP Search:
public int kmp(String text, String pattern) {
int[] next = prekmp(pattern);
int textStart = 0, patternStart = 0;
while (textStart + patternStart < text.length()) {
if (text.charAt(textStart + patternStart) == pattern
.charAt(patternStart)) {
if (patternStart == pattern.length() - 1) {
return textStart;
}
patternStart++;
} else {
if (next[patternStart] > -1) {
textStart = textStart + patternStart
- next[patternStart];
patternStart = next[patternStart];
} else {
textStart++;
patternStart = 0;
}
}
}
return -1;
}
public int kmp2(String text, String pattern) {
int[] next = prekmp(pattern);
int i = 0, j = 0;
while (i < text.length()) {
while (j >= 0 && text.charAt(i) != pattern.charAt(j))
j = next[j];
i++;
j++;
if (j == pattern.length())
return i - pattern.length();
}
return -1;
}
http://www.mathcs.emory.edu/~cheung/Courses/323/Syllabus/Text/Matching-KMP2.html
The values f(k) are computed easily using existing prefix overlap information:
Also refer to Knuth–Morris–Pratt algorithm - Wikipedia
https://weblogs.java.net/blog/potty/archive/2012/05/10/string-searching-algorithms-part-ii
Java code:
http://www.sanfoundry.com/java-program-knuth-morris-pratt-algorithm/
http://algs4.cs.princeton.edu/53substring/KMP.java.html
http://www.fmi.uni-sofia.bg/fmi/logic/vboutchkova/sources/KMPMatch_java.html
http://algs4.cs.princeton.edu/53substring/KMPplus.java.html
http://tekmarathon.com/2013/05/14/algorithm-to-find-substring-in-a-string-kmp-algorithm/
Read full article from Knuth-Morris-Pratt algorithm
http://www.mathcs.emory.edu/~cheung/Courses/323/Syllabus/Text/Matching-KMP2.html
http://www.mathcs.emory.edu/~cheung/Courses/323/Syllabus/Text/Matching-KMP3.html
Suppose the red character in the input text is the first unmatched character:
T = ???????????????????
P = aaabaaaxyz
|
T = ????aaab??????????
P = aaab???????
|
- In the above example, we can slide the pattern P 4 characters further down without missing a matching pattern !!!
Maximum overlap of a prefix:
- Let pre be a prefix of the pattern P
- MaxOverlap(pre) = the longest proper suffix that is equal to a prefix of pre
- The Maximum Overlap must be a proper suffix (i.e., it must be a substring !!!)
- If there is a mismatch at T[i] and P[j] (i.e., T[i] ≠ P[j]) and the MaxOverlap of the prefix has length k:
Then we can slide P so that the suffix and prefix aligns without missing out on a match:
- If the mismatched location is P[j], then prefix is:
- P[0 .. (j−1)] !!!
- "Fast slide" algorithm on mismatch --- psuedo code:
prefix = P[ 0..(j-1) ]; // Prefix of pattern at the mismatch k = MaxOverlap( prefix ); // Compute max overlap j = k; i0 = (i - j); // i is unchanged !
- Example:
1 2 01234567890123456789012 (ruler) i0=0 i=7 | | v v T: abadababaccabacabaabb P: abadabacb ^ | j=7
Prefix: abadaba Maximum overlap: abadaba abadaba So: k = 3
1 2 01234567890123456789012 (ruler) i0=0 i=7 | | v v T: abadababaccabacabaabb P: abadabacb ^ | j=7 Update: j = 3 (k = 3) i0 = (7-3) = 4 New situation: 1 2 01234567890123456789012 (ruler) i0=4 i=7 | | v v T: abadababaccabacabaabb P: abadabacb ^ | j=3
- Let P = p0 p1 p2 ... pk ... pm-1
- The failure function f(k) is defined as:
f(k) = MaxOverlap( "p0 p1 p2 ... pk " )
Graphically:
- We must exclude the first character p0 because the maximum overlap must be a proper suffix Example: computing the failure function
- By default, we set: f(0) = 0which will make the pattern P slide over 1 character position
Pattern:
Position: 012345
P: abacab
|
"Partial match" table (also known as "failure function")
We want to be able to look up, for each position in W, the length of the longest possible initial segment ofW leading up to (but not including) that position, other than the full segment starting at W[0] that just failed to match; this is how far we have to backtrack in finding the next match. Hence T[i] is exactly the length of the longest possible proper initial segment of W which is also a segment of the substring ending at W[i - 1]. We use the convention that the empty string has length 0. Since a mismatch at the very start of the pattern is a special case (there is no possibility of backtracking), we set T[0] = -1
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
W[i] | A | B | C | D | A | B | D |
T[i] | -1 | 0 | 0 | 0 | 0 | 1 | 2 |
Another example, more interesting and complex:
i | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
W[i] | P | A | R | T | I | C | I | P | A | T | E | I | N | P | A | R | A | C | H | U | T | E | ||
T[i] | -1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 | 3 | 0 | 0 | 0 | 0 | 0 |
algorithm kmp_table: input: an array of characters, W (the word to be analyzed) an array of integers, T (the table to be filled) define variables: an integer, pos ← 2 (the current position we are computing in T) an integer, cnd ← 0 (the zero-based index in W of the next character of the current candidate substring) (the first few values are fixed but different from what the algorithm might suggest) let T[0] ← -1, T[1] ← 0 while pos < length(W) do (first case: the substring continues) if W[pos - 1] = W[cnd] then let cnd ← cnd + 1, T[pos] ← cnd, pos ← pos + 1 (second case: it doesn't, but we can fall back) else if cnd > 0 then let cnd ← T[cnd] (third case: we have run out of candidates. Note cnd = 0) else let T[pos] ← 0, pos ← pos + 1https://weblogs.java.net/blog/potty/archive/2012/05/10/string-searching-algorithms-part-ii
public int[] prekmp(String pattern) {
int[] next = new int[pattern.length()];
next[0] = -1;
next[1] = 0;
int pos = 2, cnd = 0;
while (pos < pattern.length()) {
if (pattern.charAt(pos - 1) == pattern.charAt(cnd)) {
cnd++;
next[pos] = cnd;
} else {
cnd = next[cnd];
while (cnd > 0
&& pattern.charAt(pos - 1) != pattern.charAt(cnd))
cnd = next[cnd];
if (cnd < 0) {
next[pos] = 0;
cnd = 0;
} else {
next[pos] = cnd;
}
}
pos++;
}
return next;
}
public int[] prekmpOpt(String pattern) {
int[] next = new int[pattern.length()];
int i = 0, j = -1;
next[0] = -1;
while (i < pattern.length() - 1) {
while (j >= 0 && pattern.charAt(i) != pattern.charAt(j))
j = next[j];
i++;
j++;
next[i] = j;
}
return next;
}
(5) 1 01234567890123456789 (ruler) i=5 | v abacaabaccabacabaabb abacab ^ | j=5 T[i=5] != P[j=5] ==> Don't change i Set j = f(4) = 1 !!! (Because matching prefix ended at pos 4 !!!) Result: 1 01234567890123456789 (ruler) i=5 | v abacaabaccabacabaabb abacab ^ | j=1
KMP Search:
algorithm kmp_search: input: an array of characters, S (the text to be searched) an array of characters, W (the word sought) define variables: an integer, m ← 0 (the beginning of the current match in S) an integer, i ← 0 (the position of the current character in W) an array of integers, T (the table, computed elsewhere) while m + i < length(S) do if W[i] = S[m + i] then if i = length(W) - 1 then return m let i ← i + 1 else if T[i] > -1 then let m ← m + i - T[i], i ← T[i] else let i ← 0, m ← m + 1 (if we reach here, we have searched all of S unsuccessfully) return the length of S
public int kmp(String text, String pattern) {
int[] next = prekmp(pattern);
int textStart = 0, patternStart = 0;
while (textStart + patternStart < text.length()) {
if (text.charAt(textStart + patternStart) == pattern
.charAt(patternStart)) {
if (patternStart == pattern.length() - 1) {
return textStart;
}
patternStart++;
} else {
if (next[patternStart] > -1) {
textStart = textStart + patternStart
- next[patternStart];
patternStart = next[patternStart];
} else {
textStart++;
patternStart = 0;
}
}
}
return -1;
}
public int kmp2(String text, String pattern) {
int[] next = prekmp(pattern);
int i = 0, j = 0;
while (i < text.length()) {
while (j >= 0 && text.charAt(i) != pattern.charAt(j))
j = next[j];
i++;
j++;
if (j == pattern.length())
return i - pattern.length();
}
return -1;
}
http://www.mathcs.emory.edu/~cheung/Courses/323/Syllabus/Text/Matching-KMP2.html
The values f(k) are computed easily using existing prefix overlap information:
- f(0) = 0 (f(0) is always 0)
- f(1) is computing using (already computed) value f(0)
- f(2) is computing using (already computed) value f(0), f(1)
- f(3) is computing using (already computed) value f(0), f(1), f(2)
- And so on.
- According to the definition of f(k):
- Suppose that we know that: f(k−1) = x
- Can we use the fact that f(k−1) = x to compute f(k) ?
If px == pk, then:
f(k) = x+1
(i.e., the maximum overlap of the prefix
p0 p1 p2 .... pk-1 pk
has x+1 characters
|
0123456789
prefix = ababyababa
ababyababa
ababyababa
Conclusion:
*** We CANNOT use f(8) to compute f(9) ***
|
- To find the maximum overlap, we must slide the prefix down and look for matching letters !!!
- Let: f(k−1) = x(Note: f(k−1) is equal to some value. The above assumption simply gave a more convenient notation for this value).
If px ≠ pk, then:
- The next prefix that can be used to compute f(k) is:
p0 p1 .... px-1
i = k-1; // Try to use f(k-1) to compute f(k) x = f(i); // x = character position to match against pk if ( P[k] == P[x] ) then f(k) = f(x−1) + 1 else Use: p0 p1 .... px-1 to compute f(k) What that means in terms of program statements: i = x-1; // Try to use f(x-1) to compute f(k) x = f(i); // x = character position to match against pk
- The next prefix that can be used to compute f(k) is:
public static int[] KMP_failure_function(String P) { int k, i, x, m; int f[] = new int[P.length()]; m = P.length(); f[0] = 0; // f(0) is always 0 for ( k = 1; k < m; k++ ) { // Compute f[k] i = k-1; // First try to use f(k-1) to compute f(k) x = f[i]; while ( P.charAt(x) != P.charAt(k) ) { i = x-1; // Try the next candidate f(.) to compute f(k) if ( i < 0 ) // Make sure x is valid break; // STOP the search !!! x = f[i]; } if ( i < 0 ) f[k] = 0; // No overlap at all: max overlap = 0 characters else f[k] = f[i] + 1; // We can compute f(k) using f(i) } return(f); }
http://www.mathcs.emory.edu/~cheung/Courses/323/Syllabus/Text/Matching-KMP3.html
- In each iteration of the loop, at least one of the variables:
- i
- i0
- Therefore:
- You can increase i ≤ (i.e., at most) n times and
- You can increase k ≤ (i.e., at most) n times
- Because each time through the while loop, we will either:
- increase i by (at least) 1 or
- increase i0 by (at least) 1
# iteration ≤ 2 × n
Also refer to Knuth–Morris–Pratt algorithm - Wikipedia
https://weblogs.java.net/blog/potty/archive/2012/05/10/string-searching-algorithms-part-ii
Java code:
http://www.sanfoundry.com/java-program-knuth-morris-pratt-algorithm/
http://algs4.cs.princeton.edu/53substring/KMP.java.html
http://www.fmi.uni-sofia.bg/fmi/logic/vboutchkova/sources/KMPMatch_java.html
http://algs4.cs.princeton.edu/53substring/KMPplus.java.html
http://tekmarathon.com/2013/05/14/algorithm-to-find-substring-in-a-string-kmp-algorithm/
Read full article from Knuth-Morris-Pratt algorithm