1

Тема: Хэш на строках

http://e-maxx.ru/algo/string_hashes
У меня есть пара вопросов по этой статье:
1.Почему данная хэш-функция  не вызывает коллизий?
2.Не совсем понятно как найти хэш-функцию от подстроки.Может это для кого-то и очевидно,но у меня возникли проблемы с пониманием этого этапа.
Буду благодарен за любую помощь. smile

2

Re: Хэш на строках

Ну теоретически она может вызывать, но шанс ничтожный. В олимпиадном программировании на это закрывают глаза, потому что автор тестов не может предугадать какую именно хеш-функцию будет использовать участник, ведь даже для этой функции P можно выбрать любое, а тесты которые валят одну функцию не будут валить другую.

Пусть нам нужно найти хеш какой-то подстроки S, начиная от символа i и заканчивая j. Коефициенты при P^i, P^(i+1), ..., P^(j) и есть символы данной подстроки. Рассмотрим многочлен h(j)-h(i-1). Он имеет вид S(i)*P^i+S(i+1)P^(i+1)+...+S(j)*P^j. Теперь, разделив все на P^i получим многочлен вида S(i)+S(i+1)*P+...+S(j)*P^j, что и будем хешем такого же вида для подстроки с i-го символа по j-й. Вместо деления можно использовать умножение на P^(N-j-1), где N - длина строки S. В таком случае получим многочлен S(i)*P^(N-j-1)+S(i+1)*P^(N-j)+...+S(j)*P^(N-1). Это в какой-то мере тоже хеш подстроки, правда уже не совсем такого вида. Но если нам нужно сравнивать только подстроки, то нам не важно, какой степени этот многочлен, а следовательно, и такая хеш функция для сравнения подстрок между собой нам подходит.

3

Re: Хэш на строках

Хммм..
Например при поиске вхождений строки s1 в s мы найдём хэш-функции от всех префиксов строки s и от самой  s1.А потом при поиске проверяем чтобы  h(s1)*P^(i-1)=h(j)-h(i).
Так ведь?

4

Re: Хэш на строках

Вроде так smile

А насчёт коллизий - вот в недавнем моём контесте на codeforces мы попытались завалить хеш int64 - вот в той задаче (а там надо было проверять подстроку на палиндромность) вообще не удалось найти ни одного контртеста против хеша! (даже хоть с одной какой-нибудь базой P). Так что int64-хеши очень сложно завалить, не говоря уж про то, что можно в крайнем случае два int64 делать по разным базам smile

5 Отредактировано coder.ua (2010-05-08 16:27:01)

Re: Хэш на строках

Ну да, двухуровневый хэш при поиске подстроки лишь немного увеличит константу,но на словарных задачах его довольно сложно реализовать используя О(n) памяти.Зато ответ на запрос за О(1).
Кстати кто-нибудь реализовывал его используя О(n) памяти?

6

Re: Хэш на строках

epic fail...
Возникла проблема в реализации.. sad .Когда вычисляю h(i..j) это значение иногда бывает отрицательное(понятно по какой причине).Перечитывал статью,но ошибку в самом алгоритме не нашёл.Но в коде,несмотря на то, что я ничего не понимаю в с++, меня насторожила запись в коде: "{
    h(i) = (t(i) - 'a' + 1) * p_pow(i);
    if (i)  h(i) += h(i-1);
}
"
что означает if (i)?и как избежать искажений из-за вычислений по модулю?

7

Re: Хэш на строках

Отрицательные - просто потому что переполнился int64. Собственно всё равно, потому что везде, где мы будем использовать хеш, он будет переполняться одинаково. Т.е. все вычисления как бы производятся по модулю 2^64 (хотя и странному модулю, сдвинутому влево на 2^63 smile ).

if (i) просто о том, что хеш от префикса [0..i] равен хешу текущего символа плюс хешу от [0..i-1], если i>0.

А с вычислениями по модулю никаких хитростей быть не должно. Единственное, что надо усвоить - что при таком подходе делить на P^ будет невозможно, можно только умножать.

8

Re: Хэш на строках

Почему отрицательные это я знаю.Но ведь h[j]-h[i-1] может быть меньше 0.А вот h(s1)*p^I, где s1-искомая строка-всегда больше 0.

9

Re: Хэш на строках

Нет, потому что p^i могло стать отрицательным из-за переполнения wink