Хеширование строк: различия между версиями
Перейти к навигации
Перейти к поиску
Ctrlalt (обсуждение | вклад) Нет описания правки |
Ctrlalt (обсуждение | вклад) Нет описания правки |
||
| (не показано 11 промежуточных версий этого же участника) | |||
| Строка 1: | Строка 1: | ||
{ | h<sub>i</sub> = s<sub>0</sub>x<sup>n - 1</sup> + s<sub>1</sub>x<sup>n - 2</sup> + ... + s<sub>n - 2</sub>x + s<sub>n - 1</sub>. | ||
struct Hasher { | |||
long long mod; | |||
vector<long long> p, h; | |||
Hasher(const string &s, long long factor = 31, long long mod = 1e9 + 7) : mod(mod) { | |||
p.push_back(1); | |||
for (int i = 1; i < s.size(); i++) | |||
p.push_back(p[i - 1] * factor % mod); | |||
h.push_back(s[0] - 'a' + 1); | |||
for (int i = 1; i < s.size(); i++) | |||
h.push_back((h[i - 1] * factor % mod + s[i] - 'a' + 1) % mod); | |||
} | |||
long long getHash(int l, int r) { | |||
long long res = h[r]; | |||
if (l) | |||
res = (res - p[r - l + 1] * h[l - 1] % mod + mod) % mod; | |||
return res; | |||
} | |||
}; | |||
struct DoubleHasher { | |||
Hasher h1, h2; | |||
DoubleHasher(const string &s) : h1(s), h2(s, 29, 1e9 + 9) {} | |||
pair<long long, long long> getHash(int l, int r) { | |||
return { h1.getHash(l, r), h2.getHash(l, r) }; | |||
} | } | ||
} | }; | ||
struct Hasher2D { | |||
long long mod; | |||
vector<long long> py, px; | |||
vector<vector<long long>> h; | |||
Hasher2D(const vector<string> &a, long long factorY = 29, long long factorX = 31, long long mod = 1e9 + 7) : mod(mod) { | |||
py.push_back(1); | |||
for (int y = 1; y < a.size(); y++) | |||
py.push_back(py[y - 1] * factorY % mod); | |||
px.push_back(1); | |||
for (int x = 1; x < a[0].size(); x++) | |||
px.push_back(px[x - 1] * factorX % mod); | |||
h.assign(a.size(), vector<long long>(a[0].size())); | |||
for (int y = 0; y < a.size(); y++) { | |||
for (int x = 0; x < a[0].size(); x++) { | |||
h[y][x] = (a[y][x] - 'a' + 1) % mod; | |||
if (y) | |||
h[y][x] = (h[y][x] + h[y - 1][x] * factorY) % mod; | |||
if (x) | |||
h[y][x] = (h[y][x] + h[y][x - 1] * factorX) % mod; | |||
if (y && x) | |||
h[y][x] = ((h[y][x] - h[y - 1][x - 1] * factorY * factorX) % mod + mod) % mod; | |||
} | |||
} | |||
} | |||
| width=" | long long getHash(int yl, int xl, int yr, int xr) { | ||
| width= | long long res = h[yr][xr]; | ||
if (yl) | |||
res = (res - py[yr - yl + 1] * h[yl - 1][xr] % mod + mod) % mod; | |||
if (xl) | |||
res = (res - px[xr - xl + 1] * h[yr][xl - 1] % mod + mod) % mod; | |||
if (yl && xl) | |||
res = (res + py[yr - yl + 1] * px[xr - xl + 1] % mod * h[yl - 1][xl - 1]) % mod; | |||
return res; | |||
} | |||
}; | |||
<!--{| width="100%" | |||
| width=50% | | |||
h<sub>i</sub> = s<sub>0</sub> + s<sub>1</sub>x + s<sub>2</sub>x<sup>2</sup> + ... + s<sub>n - 1</sub>x<sup>n - 1</sup>. | |||
Для выравнивания хеши различных подстрок домножаются на x<sup>n - 1 - L</sup>. | |||
struct Hasher { | struct Hasher { | ||
long long x = 31, mod = 1e9 + 7; | |||
vector<long long> p, h; | |||
Hasher(const string &s) { | |||
p.resize(s.size()); | |||
h.resize(s.size()); | |||
p[0] = 1; | p[0] = 1; | ||
for (int i = 1; i < | h[0] = s[0] - 'a' + 1; | ||
p[i] = (p[i - 1] * | |||
for (int i = 1; i < s.size(); i++) { | |||
p[i] = p[i - 1] * x % mod; | |||
h[i] = (h[i - 1] + p[i] * (s[i] - 'a' + 1) % mod) % mod; | |||
} | |||
} | |||
long long getHash(int l, int r) { | |||
long long res = h[r]; | |||
if (l) | |||
res = (res - h[l - 1] + mod) % mod; | |||
res = res * p[p.size() - 1 - l] % mod; | |||
return res; | |||
} | } | ||
}; | |||
Этот способ непригоден для сравнения участков двух строк разной длины. В данном случае хеш более левого участка следует домножать на x<sup>|L1 - L2|</sup>. | |||
| width="10px" | | |||
| width=50% | | |||
h<sub>i</sub> = s<sub>0</sub> + s<sub>1</sub>x + s<sub>2</sub>x<sup>2</sup> + ... + s<sub>n - 1</sub>x<sup>n - 1</sup>. | |||
Для выравнивания хеши различных подстрок домножаются на (x<sup>-1</sup>)<sup>L</sup>. | |||
struct Hasher { | |||
long long x = 31, {{Changed|1=xi = 129032259,}} mod = 1e9 + 7; | |||
vector<long long> p, {{Changed|pi,}} h; | |||
Hasher(const string &s) { | |||
p.resize(s.size()); | |||
{{Changed|pi.resize(s.size());}} | |||
h.resize(s.size()); | |||
p[0] = {{Changed|1=pi[0] = }} 1; | |||
h[0] = s[0] - 'a' + 1; | h[0] = s[0] - 'a' + 1; | ||
for (int i = 1; s[i]; i | |||
h[i] = (h[i - 1] + | for (int i = 1; i < s.size(); i++) { | ||
p[i] = p[i - 1] * x % mod; | |||
{{Changed|1=pi[i] = pi[i - 1] * xi % mod;}} | |||
h[i] = (h[i - 1] + p[i] * (s[i] - 'a' + 1) % mod) % mod; | |||
} | |||
} | } | ||
long long getHash(int l, int r) { | |||
long long res = h[r]; | |||
if (l) { | |||
res = (res - h[l - 1] + mod) % mod; | |||
{{Changed|1=res = (res * pi[l]) % mod}}; | |||
} | |||
return res; | |||
} | } | ||
} | }; | ||
|} | |}--> | ||
== Ссылки == | == Ссылки == | ||
| Строка 52: | Строка 148: | ||
* [http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D0%BF%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8_%D0%B2_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B5_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%85%D0%B5%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F._%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A0%D0%B0%D0%B1%D0%B8%D0%BD%D0%B0-%D0%9A%D0%B0%D1%80%D0%BF%D0%B0 neerc.ifmo.ru — Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа] | * [http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D0%BF%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8_%D0%B2_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B5_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%85%D0%B5%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F._%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A0%D0%B0%D0%B1%D0%B8%D0%BD%D0%B0-%D0%9A%D0%B0%D1%80%D0%BF%D0%B0 neerc.ifmo.ru — Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа] | ||
* [http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D0%BD%D0%B0%D0%B8%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%B5%D0%B9_%D0%BE%D0%B1%D1%89%D0%B5%D0%B9_%D0%BF%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8_%D0%B4%D0%B2%D1%83%D1%85_%D1%81%D1%82%D1%80%D0%BE%D0%BA_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%85%D0%B5%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F neerc.ifmo.ru — Поиск наибольшей общей подстроки двух строк с использованием хеширования] | * [http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D0%BD%D0%B0%D0%B8%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%B5%D0%B9_%D0%BE%D0%B1%D1%89%D0%B5%D0%B9_%D0%BF%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8_%D0%B4%D0%B2%D1%83%D1%85_%D1%81%D1%82%D1%80%D0%BE%D0%BA_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%85%D0%B5%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F neerc.ifmo.ru — Поиск наибольшей общей подстроки двух строк с использованием хеширования] | ||
* [https://ru.algorithmica.org/cs/hashing/polynomial/ ru.algorithmica.org — Полиномиальное хеширование] | |||
* [http://habrahabr.ru/post/142589/ habrahabr.ru — Полиномиальные хеши и их применение] | * [http://habrahabr.ru/post/142589/ habrahabr.ru — Полиномиальные хеши и их применение] | ||
* [http://codeforces.com/blog/entry/4898 codeforces.com — Anti-hash test] | * [http://codeforces.com/blog/entry/4898 codeforces.com — Anti-hash test] | ||
* [http://codeforces.com/blog/entry/60445 codeforces.com — Полиномиальное хеширование + разбор интересных задач] | |||
* [https://blog.algoprog.ru/hash-no-multiply/ Калинин П. — Про хеширование без домножения] | |||
* [https://usaco.guide/gold/string-hashing?lang=cpp usaco.guide — String Hashing] | |||
Код: | Код: | ||
* [ | * [https://github.com/indy256/codelibrary/blob/master/cpp/strings/hashing.cpp codelibrary/cpp/strings/hashing.cpp] | ||
* [ | * [https://github.com/ADJA/algos/blob/master/Strings/Hashing.cpp algos/Strings/Hashing.cpp] | ||
Задачи: | Задачи: | ||
* [[:Категория: Задачи: Хеширование строк|Задачи: Хеширование строк]] | * [[:Категория: Задачи: Хеширование строк|Задачи: Хеширование строк]] | ||
[[Категория:Строки]] | [[Категория:Строки]] | ||
Текущая версия от 01:48, 18 декабря 2025
hi = s0xn - 1 + s1xn - 2 + ... + sn - 2x + sn - 1.
struct Hasher {
long long mod;
vector<long long> p, h;
Hasher(const string &s, long long factor = 31, long long mod = 1e9 + 7) : mod(mod) {
p.push_back(1);
for (int i = 1; i < s.size(); i++)
p.push_back(p[i - 1] * factor % mod);
h.push_back(s[0] - 'a' + 1);
for (int i = 1; i < s.size(); i++)
h.push_back((h[i - 1] * factor % mod + s[i] - 'a' + 1) % mod);
}
long long getHash(int l, int r) {
long long res = h[r];
if (l)
res = (res - p[r - l + 1] * h[l - 1] % mod + mod) % mod;
return res;
}
};
struct DoubleHasher {
Hasher h1, h2;
DoubleHasher(const string &s) : h1(s), h2(s, 29, 1e9 + 9) {}
pair<long long, long long> getHash(int l, int r) {
return { h1.getHash(l, r), h2.getHash(l, r) };
}
};
struct Hasher2D {
long long mod;
vector<long long> py, px;
vector<vector<long long>> h;
Hasher2D(const vector<string> &a, long long factorY = 29, long long factorX = 31, long long mod = 1e9 + 7) : mod(mod) {
py.push_back(1);
for (int y = 1; y < a.size(); y++)
py.push_back(py[y - 1] * factorY % mod);
px.push_back(1);
for (int x = 1; x < a[0].size(); x++)
px.push_back(px[x - 1] * factorX % mod);
h.assign(a.size(), vector<long long>(a[0].size()));
for (int y = 0; y < a.size(); y++) {
for (int x = 0; x < a[0].size(); x++) {
h[y][x] = (a[y][x] - 'a' + 1) % mod;
if (y)
h[y][x] = (h[y][x] + h[y - 1][x] * factorY) % mod;
if (x)
h[y][x] = (h[y][x] + h[y][x - 1] * factorX) % mod;
if (y && x)
h[y][x] = ((h[y][x] - h[y - 1][x - 1] * factorY * factorX) % mod + mod) % mod;
}
}
}
long long getHash(int yl, int xl, int yr, int xr) {
long long res = h[yr][xr];
if (yl)
res = (res - py[yr - yl + 1] * h[yl - 1][xr] % mod + mod) % mod;
if (xl)
res = (res - px[xr - xl + 1] * h[yr][xl - 1] % mod + mod) % mod;
if (yl && xl)
res = (res + py[yr - yl + 1] * px[xr - xl + 1] % mod * h[yl - 1][xl - 1]) % mod;
return res;
}
};
Ссылки
Теория:
- e-maxx.ru — Алгоритмы хэширования в задачах на строки
- neerc.ifmo.ru — Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа
- neerc.ifmo.ru — Поиск наибольшей общей подстроки двух строк с использованием хеширования
- ru.algorithmica.org — Полиномиальное хеширование
- habrahabr.ru — Полиномиальные хеши и их применение
- codeforces.com — Anti-hash test
- codeforces.com — Полиномиальное хеширование + разбор интересных задач
- Калинин П. — Про хеширование без домножения
- usaco.guide — String Hashing
Код:
Задачи: