Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4afc8c7

Browse files
committedApr 24, 2018
Add knuth.
1 parent 9081de3 commit 4afc8c7

File tree

4 files changed

+88
-2
lines changed

4 files changed

+88
-2
lines changed
 

‎README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@
4141
* **String**
4242
* [Levenshtein Distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences
4343
* [Hamming Distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/hamming-distance) - number of positions at which the symbols are different
44-
* Knuth Morris Pratt
44+
* [Knuth–Morris–Pratt algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/knuth-morris-pratt) - substring search
45+
* Rabin Karp
4546
* Longest common subsequence
4647
* longest common substring
47-
* Rabin Karp
4848
* **Search**
4949
* [Binary Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/search/binary-search)
5050
* **Sorting**
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Knuth–Morris–Pratt Algorithm
2+
3+
The Knuth–Morris–Pratt string searching algorithm (or
4+
KMP algorithm) searches for occurrences of a "word" `W`
5+
within a main "text string" `T` by employing the
6+
observation that when a mismatch occurs, the word itself
7+
embodies sufficient information to determine where the
8+
next match could begin, thus bypassing re-examination
9+
of previously matched characters.
10+
11+
## Complexity
12+
13+
- **Time:** `O(|W| + |T|)` (much faster comparing to trivial `O(|W| * |T|)`)
14+
- **Space:** `O(|W|)`
15+
16+
## References
17+
18+
- [Wikipedia](https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm)
19+
- [YouTube](https://www.youtube.com/watch?v=GTJr8OvyEVQ)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import knuthMorrisPratt from '../knuthMorrisPratt';
2+
3+
describe('knuthMorrisPratt', () => {
4+
it('should find word position in given text', () => {
5+
expect(knuthMorrisPratt('abcbcglx', 'abca')).toBe(-1);
6+
expect(knuthMorrisPratt('abcbcglx', 'bcgl')).toBe(3);
7+
expect(knuthMorrisPratt('abcxabcdabxabcdabcdabcy', 'abcdabcy')).toBe(15);
8+
expect(knuthMorrisPratt('abcxabcdabxabcdabcdabcy', 'abcdabca')).toBe(-1);
9+
expect(knuthMorrisPratt('abcxabcdabxaabcdabcabcdabcdabcy', 'abcdabca')).toBe(12);
10+
expect(knuthMorrisPratt('abcxabcdabxaabaabaaaabcdabcdabcy', 'aabaabaaa')).toBe(11);
11+
});
12+
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* @see https://www.youtube.com/watch?v=GTJr8OvyEVQ
3+
* @param {string} word
4+
* @return {number[]}
5+
*/
6+
function buildPatternTable(word) {
7+
const patternTable = [0];
8+
let prefixIndex = 0;
9+
let suffixIndex = 1;
10+
11+
while (suffixIndex < word.length) {
12+
if (word[prefixIndex] === word[suffixIndex]) {
13+
patternTable[suffixIndex] = prefixIndex + 1;
14+
suffixIndex += 1;
15+
prefixIndex += 1;
16+
} else if (prefixIndex === 0) {
17+
patternTable[suffixIndex] = 0;
18+
suffixIndex += 1;
19+
} else {
20+
prefixIndex = patternTable[prefixIndex - 1];
21+
}
22+
}
23+
24+
return patternTable;
25+
}
26+
27+
/**
28+
* @param {string} text
29+
* @param {string} word
30+
* @return {number}
31+
*/
32+
export default function knuthMorrisPratt(text, word) {
33+
let textIndex = 0;
34+
let wordIndex = 0;
35+
36+
const patternTable = buildPatternTable(word);
37+
38+
while (textIndex < text.length) {
39+
if (text[textIndex] === word[wordIndex]) {
40+
// We've found a match.
41+
if (wordIndex === word.length - 1) {
42+
return (textIndex - word.length) + 1;
43+
}
44+
wordIndex += 1;
45+
textIndex += 1;
46+
} else if (wordIndex > 0) {
47+
wordIndex = patternTable[wordIndex - 1];
48+
} else {
49+
wordIndex = 0;
50+
textIndex += 1;
51+
}
52+
}
53+
54+
return -1;
55+
}

0 commit comments

Comments
 (0)
Please sign in to comment.