Hello again!
Previously, I published a blog about a class I came up with to help people learn Hashing.
Now, I come with another type of object: Hashing with 2 modules, and 2 non-module primes.
The probability of a collision in a Hashing can be calculated as:
And with 1e6 comparisons between two substrings within the same string (usually, a problem with hashing requires this number of comparisons), with a single module it can result in collisions, and thus in solutions that give Wrong Answer.
However, the probabilities of collision in Hashing with more modules are approximately:
For 10⁶ comparisons: ≈ 2.5 × 10⁻²⁵
For 10⁹ comparisons: ≈ 2.5 × 10⁻¹⁶
For 10¹² comparisons: ≈ 2.5 × 10⁻⁷
So if in a problem you get Wrong Answer due to a collision, go win the lottery! (seriously)
Here is the class:
class HashStr{
public:
int md;
int prim;
string str;
vector<int>pot;
vector<int>hash;
HashStr(){};
HashStr(string s,const int& _md,const int& _prim){
md=_md;
prim=_prim;
str=s;
pot.push_back(1);
hash.push_back(0);
for(int i=0;i<s.size();i++){
pot.push_back((pot[i]*prim)%md);
hash.push_back((hash[i]*prim+(s[i]))%md);
}
}
HashStr(const HashStr& x){
md=x.md;
prim=x.prim;
str=x.str;
pot=x.pot;
hash=x.hash;
}
int gethash(int l,int r){
int re=(hash[r]-hash[l-1]*pot[r-l+1])%md;
return re<0?re+md:re;
}
void operator=(const HashStr& x){
md=x.md;
prim=x.prim;
str=x.str;
hash=x.hash;
pot=x.pot;
}
};
class Value{
public:
int h1,h2,h3,h4;
Value(){}
Value(const int& a,const int& b,const int& c,const int& d):h1(a),h2(b),h3(c),h4(d){}
bool operator==(const Value& v)const{
return h1==v.h1&&h2==v.h2&&h3==v.h3&&h4==v.h4;
}
bool operator<(const Value& v)const{
if(h1!=v.h1)return h1<v.h1;
if(h2!=v.h2)return h2<v.h2;
if(h3!=v.h3)return h3<v.h3;
return h4<v.h4;
}
void operator=(const Value& v){
h1=v.h1;
h2=v.h2;
h3=v.h3;
h4=v.h4;
}
};
class HashedStr{
public:
HashStr h1,h2,h3,h4;
HashedStr(){}
HashedStr(string s):h1(s,1e9+7,131),h2(s,1e9+9,131),h3(s,1e9+7,137),h4(s,1e9+9, 137){}
Value gethash(int l,int r){
return Value(h1.gethash(l,r),h2.gethash(l,r),h3.gethash(l,r),h4.gethash(l,r));
};
};
class HashMap{
public:
map<Value,int>m;
HashMap(){}
void push(const Value& v){m[v]++;}
void push(const string& s){
HashedStr v(s);
m[v.gethash(1,s.size())]++;
}
void push_all_sub(const string& s,const int&n){
HashedStr h(s);
for(int i=n;i<=s.size();i++){
m[h.gethash(i-n+1,i)]++;
}
}
void push_all_sub(const string& s){
HashedStr h(s);
for(int i=1;i<=s.size();i++){
for(int j=i;j<=s.size();j++){
m[h.gethash(i,j)]++;
}
}
}
void push_all_pref(const string& s){
HashedStr h(s);
for(int i=1;i<=s.size();i++){
m[h.gethash(1,i)]++;
}
}
void push_all_suf(const string& s){
HashedStr h(s);
for(int i=1;i<=s.size();i++){
m[h.gethash(s.size()-i+1,s.size())]++;
}
}
void take(const Value& v){m[v]--;}
void take(const string& s){
HashedStr v(s);
m[v.gethash(1,s.size())]--;
}
int count(const Value& v){return m[v];}
int count(const string& s){
HashedStr v(s);
return m[v.gethash(1,s.size())];
}
};
Usage examples:
int32_t main(){
string s="abcabcabababc";
HashStr h1(s,1e9+7,31); //1 hash
HashedStr h2(s); // 4 hashes
cout<<"HashStrOutputs:"<<endl<<endl;
cout<<h1.gethash(1,2)<<endl; //hash of substring "ab"
cout<<h1.gethash(1,5)<<endl; //hash of substring "abcab"
cout<<h1.gethash(4,8)<<endl; //hash of substring "abcab"
cout<<endl<<"HashedStrOutputs:"<<endl<<endl;
cout<<(h2.gethash(1,5)==h2.gethash(4,8))<<endl; //comparing "abcab" with "abcab"
// abcabcabababc
// ^ ^
// abcab
// ^ ^
// abcab
cout<<(h2.gethash(7,9)==h2.gethash(9,11))<<endl; //comparing "aba" with "aba"
cout<<(h2.gethash(1,5)==h2.gethash(7,11))<<endl<<endl; //comparing "abcab" with "ababc"
cout<<"HashMapOutputs:"<<endl<<endl;
HashMap m;
m.push("ab");
m.push("abab");
m.push("ab");
m.push("ab");
cout<<m.count("ab")<<endl<<endl; //"ab" pushed 3 times
HashMap m2;
m2.push_all_sub("abcabc"); //This push: "a","b","c","a","b","c","ab","bc","ca","ab","bc","abc"
//"bca","cab","abc","abca","bacb","cabc","abcab","bcabc","abcabc"
cout<<m2.count("ab")<<endl<<endl;
HashedStr h("abcabc");
Value a=h.gethash(1,1); //Multiple-mod-hash-value of "a"
Value b=h.gethash(1,2); //Multiple-mod-hash-value of "ab"
Value c=h.gethash(3,6); //Multiple-mod-hash-value of "cabc"
cout<<m2.count(a)<<endl; //"a" pushed 2 times
cout<<m2.count(b)<<endl; //"ab" pushed 2 times
cout<<m2.count(c)<<endl<<endl; //"cabc" pushed 1 times
HashMap m3;
m3.push_all_pref("abcdefg"); //This push: "a","ab","abc","abcd","abcde","abcdef","abcdefg"
m3.push_all_suf("abcdefg"); //This push: "g","fg","efg","defg","cdefg","bcdefg","abcdefg"
cout<<m3.count("a")<<endl; //"a" pushed 1 time
cout<<m3.count("abcdefg")<<endl; //abcdefg pushed 2 times
m3.take("a");
cout<<m3.count("a")<<endl; //"a" doesnt exist
}
I hope this can be very helpful, thank you for reading me :D







