Rolling hash is used to avoid rehashing the entire string when calculating hash values of the substrings of a given string. In a rolling hash, the new hash value is rapidly calculated using only the old hash value. This allows two strings to be compared in constant time.
So, we are doing the calculation for “bc” chars in bcd again.
Rolling hash works on the priciple that while finding the hash value of the next substring, the window is moved forward only by dropping one character and adding another.In this case character ‘a’ is removed from substring abc and character ’d’ is added next to it to get the substring bcd.
So, we do not need to rehash the string again.Instead, we can substract the hash code corresponding to the first character from the first hash value,multiply the result by the considered prime number and add the hash code corresponding to the next character to it.
[!Decision] Keep Smaller Power on Base at end
When we calculate rolling hash, we don’t have to worry about division, and we use multiplicaton everywhere.
We can use the variant where we keep the smaller power at the end, as then when
H=( c1 * a ^ k-1 + c2 * a ^ k-2 + c3 * a ^ k-3. . . . + c_k * a0 ) % m
where a is a constant, c1,c2, … ck are the input characters and m is a large prime number, since the probability of two random strings colliding is about ≈ 1/m.
Then, the hash value of next substring,Hnxt using rolling hash can be defined as:-
1
H_nxt=( ( H - c1 * a ^ k-1 ) * a + c_k+1_ * a0 ) % m
publicclassSolution {
privatefinalint p = 31;
privatefinalint m = (1 << 31) - 1;
// Utility function to calculate a^b % mpubliclongpower(long a, int b) {
long result = 1;
while (b > 0) {
if ((b & 1) != 0) {
result = (result * a) % m;
}
a = (a * a) % m;
b >>= 1;
}
return result;
}
// Function to calculate the initial hash of a substringpublicinthashCode(String s) {
int code = 0;
for (int i = 0; i < s.length(); i++) {
code = (int) ((code + (s.charAt(i) * power(p, s.length() - i - 1)) % m) % m);
}
return code;
}
// Function to calculate the rolling hashpublicintrollingHashCode(int prevHash, char left, char right, long windowPower) {
return (int) ((((prevHash - (left * windowPower) % m) + m) % m * p % m + right) % m);
}
publicstaticvoidmain(String[] args) {
Solution solution =new Solution();
String text ="abcd";
String pattern ="bcd";
int windowLength = pattern.length();
long windowPower = solution.power(solution.p, windowLength - 1);
int initialHash = solution.hashCode(text.substring(0, windowLength));
System.out.println("Initial Hash: "+ initialHash); // Output: hash of "abc"int rollingHash = solution.rollingHashCode(initialHash, text.charAt(0), text.charAt(windowLength), windowPower);
System.out.println("Rolling Hash: "+ rollingHash); // Output: hash of "bcd" }
}