Реверс хэш-функции
Есть функция хэшировния строки c символами A-Za-z0-9_. Как её обратить, чтобы можно было перебирать строки с одинаковым хэшем? Иными словами, нужно написать что-то наподобие генератора строк (до 15000) с одинаковым хэшем.
const int p = 31;
size_t operator()(const string& s) const {
size_t hash = 0, p_pow = 1;
for (size_t i = 0; i < s.size(); ++i) {
hash += (s[i] - 'a' + 1) * p_pow;
p_pow *= p;
}
return hash;
}
Ответы (2 шт):
Ваш «хэш» это просто полином вида S = an×31n + … + a1×31 + a0.
Где все ak имеют значения из списка -48…-39 (0-9), -31…-6 (A-Z), -1 (_) и 1…26 (a-z).
Для примера возьмём S = 20.
Посчитаем остаток от деления на 31. S % 31 = 20. (Ну да, немножко тривиально).
Очевидно что ak при k >= 1 никак не влияют на этот остаток. Смотрим какие значения a0 могут дать такой остаток. Это значения 20, -11 и -42. Т.е. первый символ нашей строки это t, U или 6.
не дописал…
В общем, выросло следующее. Не уверен, что приведённый код перебирает все доступные строки заданной длины, но может генерировать некоторое множество строк с одинаковым хэшем.
void recursiveSearch( size_t hash, std::string s ){
if( hash == 0 ){
// Строка найдена
// ...
return;
}
if( s.size() < 12 ) // Ограничить размер строки, иначе некая бесконечная строка может иметь ненулевой хэш
for( auto q : ab ) // Для каждого символа алфавита
{
if( ( hash - q ) % 31 == 0 ) // Если символ подходящий
// Искать подпоследовательность(-и)
recursiveSearch( ( hash - q ) / 31, s + std::string( 1, static_cast<char>( q + 'a' - 1 ) ) );
}
}
Группа вывода:
OPHRBCBBBBBBBBa OPHRBCBBBBBBBa OPHRBCBBBBBBa OPHRBCBBBBBa OPHRBCBBBBa OPHRBCBBBa OPHRBCBBa OPHRBCBa OPHRBCa OPHRBb