Этот Code Golf был вдохновлен недавней статьей Daily WTF, « Вы не можете справиться с истиной»! , который показывает сравнение строк, записанное в виде:
String yes = "YES";
if ((delay.hashCode()) == yes.hashCode())
Представьте себе проблему, которую это вызвало бы для команды Стива, если бы String.hashCode
метод Java был реализован таким образом "YES".hashCode() == "NO".hashCode()
. Итак, проблема, которую я предлагаю здесь:
Напишите как можно меньше символов хеш-функции (я ее назову
h
) со строковым параметром и целочисленным возвращаемым значением, таким, чтоh("YES")
равноh("NO")
.
Конечно, это было бы тривиально сделать с функцией like def h(s): return 0
, которая создает хеш-коллизию для каждой строки. Чтобы сделать этот вызов более интересным, вы должны соблюдать следующее дополнительное правило:
Из других 18 277 возможных строк , состоящих из трех или менее заглавных букв (ASCII
^[A-Z]{0,3}$
), не должна быть ни одного хэша столкновения.
Пояснение (на это указывает Heiko Oberdiek): входная строка может содержать символы, отличные от A-Z
, и ваш код должен иметь возможность хешировать произвольные строки. (Тем не менее, вы можете предположить, что ввод является символьной строкой, а не нулевым указателем или объектом какого-либо другого типа данных.) Однако, не имеет значения, какое возвращаемое значение для строк, которые не совпадают ^[A-Z]{0,3}$
, если это целое число
Кроме того, чтобы скрыть намерение этой функции:
Ваш код не должен содержать буквы «Y», «E», «S», «N» или «O» (в верхнем или нижнем регистре) внутри символьных или строковых литералов.
Конечно, это ограничение не распространяется на ключевые слова языка, поэтому else
, return
и т.д. все в порядке.
YESNO
для проверки этого конкретного исключения.Ответы:
GolfScript: 19 символов (24 символа для именованной функции)
Это тело функции. Присвоение его именованной функции
h
занимает еще пять символов:(Последняя точка с запятой может быть опущена, если вы не против оставить копию кода в стеке.)
Ядро хэш - функции является
26base
, которая вычисляет сумму (26 п - к · к ; к = 1 .. п ), где п есть число символов во входных данных и к обозначает ASCII код K -го Введите символ Для входных данных, состоящих из прописных букв ASCII, это хеш-функция без столкновений. Остальная часть кода сравнивает результат с 2107 (хэш-кодом ) и, если они равны, добавляет 59934, чтобы получить 2701 + 59934 = 62041, хеш-код .NO
YES
Например вывод, посмотрите эту онлайн-демонстрацию с тестовыми примерами .
источник
h('DXP') == h('KK') == 65884
.lambda w:sum(ord(c)*26**i for i,c in enumerate(reversed(w*9)))%102983
)32-битный Python 2.x (19)
RSA использует модуль полупростой передачи, и это делает его безопасным, поэтому использование его с моим алгоритмом хеширования, несомненно, сделает его еще лучше! 1
Это чисто математическая функция, она работает для всех строк (черт возьми, работает для любого хэшируемого объекта Python) и не содержит никаких условных или специальных символов! 32-битный Python обычно вызывается так же, как и
python-32
в большинстве систем, в которых установлено 2 .Я проверил это, и он возвращает 18 278 различных значений для 18 279 строк, состоящих из 3 букв или менее. Назначение этой функции занимает еще 11 байтов:
и
h('YES') == h('NO') == 188338253
.64-битный Python 2.x (19)
Та же сделка, что и выше.
Чтобы придумать эти цифры, было использовано немного модульной математики. Я искал функцию
f
и модульn
, чтобыhash(f('YES')) % n == hash(f('NO')) % n
. Это эквивалентно тестированию, котороеn
делитd = hash(f('YES')) - hash(f('NO'))
, то есть мы должны только проверить факторыd
для подходящих значенийn
.В идеале
n
это должно быть около 20000 ** 2, чтобы уменьшить вероятность столкновения с парадоксом дня рождения. Нахождение подходящегоn
оказывается методом проб и ошибок, играя со всеми факторамиd
(обычно их не так много) и различными вариантами выбора функцииf
. Обратите внимание, что метод проб и ошибок необходим только потому, что я хотел сделатьn
как можно меньше (для игры в гольф). Если бы это не было требованием, я мог бы просто выбрать вd
качестве моего модуля, который обычно достаточно велик.Также обратите внимание, что вы не можете использовать этот трюк, используя just
f(s) = s
(функцию тождества), потому что крайний правый символ строки имеет по существу линейную связь (фактическиXOR
связь) с конечным хешем (другие символы вносят гораздо более нелинейный вклад ). Следовательно, повторение строки гарантирует, что различия между строками усиливаются, чтобы исключить эффект изменения только самого правого символа.1 Это чепуха.
2 Хэширование строки Python зависит от основной версии (2 против 3) и битности (32-разрядная или 64-разрядная). Это не зависит от платформы AFAIK.
источник
hash('YES'*9)
имеет34876679
как фактор, аhash('NO'*9)
имеет34876679+537105043
как фактор. Но как вы узнали, что537105043
это хороший модуль? т.е. он не совершал других столкновений?Perl,
534940 байтКонтрольная работа:
Хеш-значения для
YES
иNO
одинаковы, и есть 18279 строк^[A-Z]{0,3}$
, которые не содержат коллизий, кроме единственной коллизии дляYES
иNO
.Ungolfed:
Старая версия, 49 байт
Поскольку новый алгоритм немного отличается, я сохраняю старую версию.
Контрольная работа:
Ungolfed:
Редактирование:
"\0"
качестве байта заполнения экономит 4 байта по сравнению с$"
.источник
5457241
и20047
откуда? Как вы рассчитываете эти числа? Заранее спасибо.YES
в шестнадцатеричном виде есть594553
. 0x594553 = 5850451.NO
в гексе есть4e4f
. 0x4e4f = 20047.Python: 63
Невероятно слабое решение:
Он работает, интерпретируя алфавитно-цифровые строки как числа base-36 и возвращая 0 для всего остального. Существует явный особый случай, чтобы проверить возвращаемое значение 852 (НЕТ) и вернуть вместо него 44596 (ДА).
источник
try:
и всю третью линию. Вы также можете сохранить несколько укусов, поместив каждую логическую строку в одну и ту же фактическую строку, разделенную точкой с запятой (def h(s):r=int(s,36);return(r,44596)[r==852]
)Pure Bash, 29 байт (функциональное тело)
Это просто обрабатывает входную строку как базовое число 36 и преобразует в десятичную, а затем обрабатывает особый
NO
случай.Выход:
источник
Рубин, 51 байт
код тестирования:
выход :
источник
Javascript ( ES6 ) 54 байта
источник
Ява -
9477раскатали:
Повествование - для
f(s) = BigInteger(s.getBytes())
:f("YES") xor f("NO") = 5835548
f("YES") xor 5835548 = f("NO")
f("YES") - (f("YES") xor 5835548) = f("NO") - (f("NO") xor 5835548)
я прав?источник
CJam, 15 байтов
Работает как решение для GolfScript ниже. Попробуйте онлайн.
GolfScript, 17 байт
Этот подход основан на ответах nneonneo и Ilmari Karonen .
Как это устроено
Выбор алгоритма
Начнем с того
{b base}:h
, что входная строка считается числом base-b. Покаb > 25
,h
inyective.Мы получим столкновение для строк «YES» и «NO», если изменим
h
следующим образом:,{x base n}:h
гдеn
это делитель"YES" h "NO" h -
.К сожалению, это означает, что мы также получим столкновение, например,
YET
иNP
. Чтобы предотвратить это, мы должны изменить число base-b нелинейным образом, прежде чем принимать модуль.Самый короткий способ сделать это в GolfScript - это умножить число base-b на себя (т. Е. Возвести его в квадрат).
h
в настоящее время{base b .* n %}:h
.Осталось только найти подходящие значения для
b
иn
. Мы можем сделать это грубой силой:Кратчайшие возможные значения для
b n
:тестирование
источник
JavaScript (ES6) - 38 символов (33 символа функции тела)
Тестовые случаи:
Объяснение:
Прежде всего, позвольте мне представить вам
NaN
- «Не число» - в JavaScript. Это число:Как:
Его особенность в том, что он никогда не сравнится с собой . Моя функция возвращает,
1
если строка являетсяYES
илиNO
, иNaN
для любой другой строки.Таким образом, это не нарушает правила, потому что для любой другой строки не будет коллизии хеша;) (
NaN !== NaN
показано выше в тестовых примерах).И моя мечта сбылась: победить Bash, Perl и Ruby по длине кода!
Код Ungolfed:
Если это значение
"WUVT"
или"Tk8="
, верните1
. Остальное, возвращениекоторый был бы
NaN
.источник
^\d+$
. И JS относится кNaN
числу. Вы можете умножить его на число, сложить, разделить, вычесть так же, как с числами. Это особое свойство JavaScript. Там нет никакого вреда в использовании этого. Это то, что мы называем изменением правил ;)Object.is()
и утверждать, что это все еще столкновение ...==
для сравнения оператор равенства ( ), что гарантирует отсутствие коллизий хешей для любой строки, кроме «YES» или «NO».NaN
не считается , как столкновение кажется дешевым, это решение имеет столкновение с строкамиNA
черезNP
иYEQ
черезYET
Python 92
Функция хеширования объединяет порядковые значения символов ASCII, а оператор print гарантирует, что два желаемых входа сталкиваются.
источник
ECMAScript 6 (30 байт)
Я пытался избежать назначения переменных, возврата и ключевого слова функции, и это выглядит как отличный способ избежать всей этой ерунды (в некотором смысле это также похоже на функциональное программирование). В отличие от других решений, это не зависит от
btoa
илиatob
, что не ECMAScript 6, а HTML5.0+
необходимо, чтобы он мог анализировать произвольные строки.источник
a=>parseInt(0+a,36)-852||43744
Ява - 45 (или 62?)
Я понятия не имею, как правильно оценить, учитывая, что нужно для запуска программы на Java, нужно ли включать определение функции? Не стесняйтесь редактировать и корректировать мой счет соответствующим образом. В настоящее время я забиваю так же, как и ответ @OldCurmudgeon. Добавьте 17 для,
int h(String t){}
если это требуется:Разряженный с испытательным ремнем безопасности:
источник
И проигравший это ...
Конвейер, 145 символов
По сути, эта программа делает что-то вроде базовых 26 символов. После этого он проверяет, равен ли хеш-код 12999 (хэш-код YES) и, если это так, выдает 404 (хэш-код NO), иначе он просто распечатает хеш-код.
Conveyor - это язык, созданный мной, который в настоящее время находится на стадии бета-тестирования, но его переводчик, а также некоторые примеры и исходный код можно найти здесь: https://github.com/loovjo/Conveyor.
источник
C # 4.5 (112 байт)
Рабочая (?) Версия попытки подземного монорельса, в C #. Объединяет байты в строке в 32-разрядное целое число (работает только до 4 символов), затем сравнивает результат ИЛИ с результатом для «ДА» и «НЕТ» соответственно, а затем ИЛИ вместе.
Хотя в какой-то момент он может столкнуться, это не должно происходить ни за какие ^ [AZ] {2,3} $, кроме «ДА» и «НЕТ».
источник
Без комментариев - 31 (содержание функции: 26)
Довольно простое решение. ;) Работает для всех без исключения строк UTF-8.
ОБЪЯСНЕНИЕ:
'
это, очевидно, функция. Во-первых, он проверяет,*
равен ли (это ввод)|,,|+|"#|
(|NO|
). Если это так, он возвращает|, |+|-%3|
(|YES|
), иначе он просто возвращается*
.источник
С 54
Преобразовать строку в целое число - «NO» и умножить ее на то же значение + «NO» - «YES», чтобы получить 0 для «NO» и «YES» и ненулевое значение для любой другой строки в указанном диапазоне.
Все значения на компьютере с Windows 7, если есть какие-либо порядковые номера.
источник
Stax ,
1211 байтЗапустите и отладьте его
Преобразует ввод как base-36, вычитает 852, затем заменяет 0 на 43744. Это порт превосходного решения Конрада .
источник
CoffeeScript - 36
Должен возвращаться
1
дляYES
иNO
, и всякая искаженная ерундаatob
производит для всего остального, что не является строкой base64.Эквивалент JavaScript ( не код JS от компилятора CS):
источник
_
когда ввод не «ДА» или «НЕТ».Вот супер хромая. ТАК ГЛАВНО, ЭТО НЕ ДАЖЕ РАБОТАЕТ
Python 2,7 - 79 байтСначала мы получаем сумму (значение ascii каждого символа) * 100 ^ (позиция этого символа в строке). Затем мы умножаем (этот результат - 7978) и (этот результат - 836989), чтобы получить наш окончательный ответ. 7978 и 836989 - это результаты для «ДА» и «НЕТ» первого бита, поэтому для ДА и НЕТ мы умножаем на 0.
Это не должно иметь каких-либо столкновений? Мне не хочется тестировать 18000 возможных контрпримеров, но если произошло непреднамеренное столкновение, я могу добавить еще 0,
100
и тогда действительно не должно быть никаких столкновений.Разочарован тем, что я не мог использовать
lambda
для этого, но я не хотел делать весь расчет дважды, поэтому мне пришлось сохранить его в переменной.Пожалуйста, не позволяйте этой победе. Это супер хромая, и я этого не заслуживаю.
источник