Skip to content

Commit 158d5ff

Browse files
committed
String Hashing
Implementation of String Hashing using double hashing technique.
1 parent 13b5d62 commit 158d5ff

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.thealgorithms.strings;
2+
3+
import java.math.BigInteger;
4+
import java.util.Random;
5+
6+
/**
7+
* @author RAJ ROY (https://github.com/RAJ8664)
8+
*
9+
* An implementation of string hashing algorithm using double hashing.
10+
* This implementation computes hash values for substrings of a given string, which can be
11+
* used for efficient substring comparisons or detecting duplicate substrings.
12+
*
13+
* This implementation uses two hash functions with distinct large prime moduli to reduce
14+
* the probability of collisions. It also precomputes modular inverses to efficiently
15+
* handle division operations in modular arithmetic.
16+
*/
17+
public class StringHashing {
18+
// Arrays to store the hash values for two hash functions
19+
long[] hash1, hash2;
20+
21+
// Arrays to store the modular inverses for two hash functions
22+
long[] inv1, inv2;
23+
24+
int n; // Length of the input string
25+
26+
// Multiplier used in the hash function (base of polynomial hashing)
27+
static int multiplier = 43;
28+
29+
// Random object for generating large prime numbers
30+
static final Random rnd = new Random();
31+
32+
// Large prime numbers used as moduli for the hash functions
33+
static final int mod1 = BigInteger.valueOf((int) (1e9 + rnd.nextInt((int) 1e9))).nextProbablePrime().intValue();
34+
static final int mod2 = BigInteger.valueOf((int) (1e9 + rnd.nextInt((int) 1e9))).nextProbablePrime().intValue();
35+
36+
// Modular inverses of the multiplier with respect to mod1 and mod2
37+
static final int invMuresiplier1 = BigInteger.valueOf(multiplier).modInverse(BigInteger.valueOf(mod1)).intValue();
38+
static final int invMuresiplier2 = BigInteger.valueOf(multiplier).modInverse(BigInteger.valueOf(mod2)).intValue();
39+
40+
/**
41+
* Constructor for computing the hash values and modular inverses for a given string.
42+
*
43+
* @param s the input string for which the hash values are to be precomputed
44+
*/
45+
public StringHashing(String s) {
46+
n = s.length();
47+
hash1 = new long[n + 1]; hash2 = new long[n + 1];
48+
inv1 = new long[n + 1]; inv2 = new long[n + 1];
49+
inv1[0] = 1; inv2[0] = 1;
50+
long p1 = 1, p2 = 1; // Power of the multiplier for hash1 and hash2 respectively;
51+
52+
for (int i = 0; i < n; i++) {
53+
// Compute the hash for mod1
54+
hash1[i + 1] = (hash1[i] + s.charAt(i) * p1) % mod1;
55+
p1 = p1 * multiplier % mod1;
56+
inv1[i + 1] = inv1[i] * invMuresiplier1 % mod1;
57+
58+
// Compute the hash for mod2
59+
hash2[i + 1] = (hash2[i] + s.charAt(i) * p2) % mod2;
60+
p2 = p2 * multiplier % mod2;
61+
inv2[i + 1] = inv2[i] * invMuresiplier2 % mod2;
62+
}
63+
}
64+
65+
/**
66+
* Retrieves the hash value for a substring of length `len` starting at index `i`.
67+
*
68+
* @param i the starting index of the substring
69+
* @param len the length of the substring
70+
* @return a combined hash value (high 32 bits from hash1 and low 32 bits from hash2)
71+
*/
72+
public long getHash(int i, int len) {
73+
return (((hash1[i + len] - hash1[i] + mod1) * inv1[i] % mod1) << 32)
74+
+ (hash2[i + len] - hash2[i] + mod2) * inv2[i] % mod2;
75+
}
76+
77+
/**
78+
* Retrieves the hash value for a substring between indices `x` and `y` (inclusive).
79+
*
80+
* @param x the starting index of the substring
81+
* @param y the ending index of the substring (inclusive)
82+
* @return a combined hash value for the substring
83+
*/
84+
public long getHashbounds(int x, int y) {
85+
return getHash(x, y - x + 1);
86+
}
87+
}

0 commit comments

Comments
 (0)