Compare numbers instead of strings: hash each window with a rolling hash and only verify on a hash match — O(n+m) average.
Rabin-Karp flips string matching into *number* matching. It turns the pattern, and every equally-long window of the text, into a number called a hash. Equal strings always hash to the same number, so any window whose hash differs from the pattern's can be skipped instantly — without comparing a single character. The magic that keeps it fast is the rolling hash: each new window's number is computed from the previous one in a single step.
Pick a base d (say the alphabet size) and a prime modulus q. A length-m string is read like a base-d number, taken mod q. For text "31415", base 10, the first 3-char window "314" hashes to 314 mod q; the next window "141" to 141 mod q, and so on. The pattern is hashed the same way, once.
To slide from window "314" to "141" you do not rebuild from scratch. You drop the leading digit, shift left (multiply by the base), and add the new trailing digit — all mod q. With h = d^(m-1) mod q precomputed, the update is a constant-time formula.
// roll the hash one position to the right
// drop text[s], bring in text[s + m]
next = (d * (hash - text[s] * h) + text[s + m]) % q;
if (next < 0) next += q; // keep it non-negativeq keeps collisions rare and the average cost linear.