Rabin Karp Algorithm
Algorithm · Stretch
Step through it: String Matching pattern
Step 1 of 5
Goal: find "abc" inside "ababcab". Slide the pattern along the text and compare letter by letter.
Step 2 of 5
At position 0: a matches, b matches, then c meets a. Mismatch.
Step 3 of 5
The slow way starts over one step later and re-reads letters. Clever methods (KMP and friends) remember that "ab" already matched, so they jump ahead and never re-read the text.
Step 4 of 5
Match found at position 2. The work is about n + m instead of n × m. This family is string matching.
Step 5 of 5
Your turn.
Complexity
Time Complexity
For text of length n and p patterns of combined length m, its average
worst-case time is O(n * m).
Space Complexity
and best case running time is O(n + m) in space O(p), but its
In computer science, the Rabin–Karp algorithm or Karp–Rabin algorithm is a string searching algorithm created by Richard M. Karp and Michael O. Rabin (1987) that uses hashing to find any one of a set of pattern strings in a text.
Algorithm
The Rabin–Karp algorithm seeks to speed up the testing of equality of
the pattern to the substrings in the text by using a hash function. A
hash function is a function which converts every string into a numeric
value, called its hash value; for example, we might
have hash('hello') = 5. The algorithm exploits the fact
that if two strings are equal, their hash values are also equal. Thus,
string matching is reduced (almost) to computing the hash value of the
search pattern and then looking for substrings of the input string with
that hash value.
However, there are two problems with this approach. First, because there are so many different strings and so few hash values, some differing strings will have the same hash value. If the hash values match, the pattern and the substring may not match; consequently, the potential match of search pattern and the substring must be confirmed by comparing them; that comparison can take a long time for long substrings. Luckily, a good hash function on reasonable strings usually does not have many collisions, so the expected search time will be acceptable.
Hash Function Used
The key to the Rabin–Karp algorithm's performance is the efficient computation of hash values of the successive substrings of the text. The Rabin fingerprint is a popular and effective rolling hash function.
The polynomial hash function described in this example is not a Rabin fingerprint, but it works equally well. It treats every substring as a number in some base, the base being usually a large prime.
Application
A practical application of the algorithm is detecting plagiarism. Given source material, the algorithm can rapidly search through a paper for instances of sentences from the source material, ignoring details such as case and punctuation. Because of the abundance of the sought strings, single-string searching algorithms are impractical.
Code
import PolynomialHash from '../../cryptography/polynomial-hash/PolynomialHash';
/**
* @param {string} text - Text that may contain the searchable word.
* @param {string} word - Word that is being searched in text.
* @return {number} - Position of the word in text.
*/
export default function rabinKarp(text, word) {
const hasher = new PolynomialHash();
// Calculate word hash that we will use for comparison with other substring hashes.
const wordHash = hasher.hash(word);
let prevFrame = null;
let currentFrameHash = null;
// Go through all substring of the text that may match.
for (let charIndex = 0; charIndex <= (text.length - word.length); charIndex += 1) {
const currentFrame = text.substring(charIndex, charIndex + word.length);
// Calculate the hash of current substring.
if (currentFrameHash === null) {
currentFrameHash = hasher.hash(currentFrame);
} else {
currentFrameHash = hasher.roll(currentFrameHash, prevFrame, currentFrame);
}
prevFrame = currentFrame;
// Compare the hash of current substring and seeking string.
// In case if hashes match let's make sure that substrings are equal.
// In case of hash collision the strings may not be equal.
if (
wordHash === currentFrameHash
&& text.substring(charIndex, charIndex + word.length) === word
) {
return charIndex;
}
}
return -1;
}References
Practice
String Matching
- Find the Index of the First Occurrence in a StringEasy
- Repeated Substring PatternEasy
- Is SubsequenceEasy
- Rotate StringEasy
- Longest Palindromic SubstringMedium
- Palindromic SubstringsMedium
- Repeated String MatchMedium
- One Edit DistanceMedium
- Shortest PalindromeHard
- Longest Happy PrefixHard
- Longest Duplicate SubstringHard
- Edit DistanceHard
- Wildcard MatchingHard
Spotted a mistake or something unclear? Report it on GitHub.