Dieser Code Golf wurde von dem kürzlich erschienenen WTF-Artikel " You Can't Handle the True!" Inspiriert. , der einen Zeichenfolgenvergleich enthält, der wie folgt geschrieben wurde:
String yes = "YES";
if ((delay.hashCode()) == yes.hashCode())
Stellen Sie sich die Schwierigkeiten vor, die es für Steves Team verursacht hätte, wenn Javas String.hashCode
Methode einfach so implementiert worden wäre "YES".hashCode() == "NO".hashCode()
. Die Herausforderung, die ich hier vorschlage, ist:
Schreiben Sie in möglichst wenigen Zeichen eine Hash-Funktion (ich nenne sie
h
) mit einem String-Parameter und einem ganzzahligen Rückgabewert, derh("YES")
gleich isth("NO")
.
Das wäre natürlich trivial, wenn es um eine Funktion geht def h(s): return 0
, die für jeden String eine Hash-Kollision erzeugt . Um diese Herausforderung interessanter zu gestalten, müssen Sie die folgenden zusätzlichen Regeln einhalten:
Von den anderen 18 277 möglichen Zeichenfolgen, die aus drei oder weniger ASCII-Großbuchstaben (
^[A-Z]{0,3}$
) bestehen, dürfen keine Hash-Kollisionen vorliegen .
Klarstellung (darauf hingewiesen von Heiko Oberdiek): Die Eingabezeichenfolge kann andere Zeichen als enthalten A-Z
, und Ihr Code muss in der Lage sein, beliebige Zeichenfolgen zu hashen. (Sie können davon ausgehen , jedoch, dass die Eingabe ist eine Zeichenkette , anstatt ein Null - Zeiger oder ein Objekt aus einem anderen Datentyp.) Allerdings ist es egal , was der Rückgabewert für Strings, die nicht übereinstimmen ^[A-Z]{0,3}$
, solange Es ist eine ganze Zahl.
Um die Absicht dieser Funktion zu verschleiern:
Ihr Code darf keine Buchstaben 'Y', 'E', 'S', 'N' oder 'O' (in Groß- oder Kleinbuchstaben) in Zeichen- oder Zeichenfolgenliteralen enthalten.
Natürlich ist diese Beschränkung auf Sprache Schlüsselwörter nicht gelten, so else
, return
etc. sind in Ordnung.
YESNO
, um nach dieser bestimmten Ausnahme zu suchen.Antworten:
GolfScript: 19 Zeichen (24 Zeichen für benannte Funktion)
Dies ist der Hauptteil der Funktion. Das Zuweisen zu einer benannten Funktion
h
erfordert fünf weitere Zeichen:(Das letzte Semikolon kann weggelassen werden, wenn es Ihnen nichts ausmacht, eine Kopie des Codes auf dem Stapel zu lassen.)
Der Kern der Hash - Funktion ist
26base
, die Summe berechnet (26 n - k · a k ; k = 1 .. n ), wobei n die Anzahl der Zeichen in der Eingabe und a k bezeichnet den ASCII - Code des k -ten Eingabezeichen. Bei Eingaben, die aus ASCII-Großbuchstaben bestehen, handelt es sich um eine kollisionsfreie Hash-Funktion. Der Rest des Codes vergleicht das Ergebnis mit 2107 (dem Hash-Code vonNO
) und addiert, wenn sie gleich sind, 59934 zu 2701 + 59934 = 62041, dem Hash-Code vonYES
.Beispielausgabe siehe diese Online-Demo mit Testfällen.
quelle
h('DXP') == h('KK') == 65884
.lambda w:sum(ord(c)*26**i for i,c in enumerate(reversed(w*9)))%102983
)32-Bit-Python 2.x (19)
RSA verwendet ein Semiprime-Modul und das macht es sicher. Wenn Sie also eines mit meinem Hash-Algorithmus verwenden, wird es mit Sicherheit noch besser! 1
Dies ist eine reine mathematische Funktion, die für alle Zeichenfolgen funktioniert (Hölle, funktioniert für jedes hashbare Python-Objekt) und keine Bedingungen oder Sonderfälle enthält! 32-Bit-Python kann normalerweise wie
python-32
auf den meisten Systemen aufgerufen werden, auf denen beide installiert sind 2 .Ich habe dies getestet und es gibt 18.278 verschiedene Werte für die 18.279 3-Buchstaben- oder weniger-Großbuchstaben-Zeichenfolgen zurück. Das Zuweisen zu einer Funktion dauert 11 weitere Bytes:
und
h('YES') == h('NO') == 188338253
.64-Bit-Python 2.x (19)
Gleiches Angebot wie oben.
Um diese Zahlen zu erhalten, wurde ein bisschen modulare Mathematik verwendet. Ich suchte nach einer Funktion
f
und einemn
solchen Modulhash(f('YES')) % n == hash(f('NO')) % n
. Dies ist gleichbedeutend mit einem Test, dern
dividiertd = hash(f('YES')) - hash(f('NO'))
, dh wir müssen nur die Faktoren vond
auf geeignete Werte von überprüfenn
.Das Ideal
n
liegt in der Nähe von 20000 ** 2, um die Wahrscheinlichkeit einer Geburtstags-Paradox-Kollision zu verringern. Das Finden einer geeigneten Funktionn
erweist sich als Versuch und Irrtum, wenn man mit allen Faktorend
(normalerweise gibt es nicht viele) und verschiedenen Auswahlmöglichkeiten für die Funktion spieltf
. Beachten Sie jedoch, dass der Versuch und Irrtum nur erforderlich ist, weil ichn
so klein wie möglich machen wollte (zum Golfen). Wenn das keine Voraussetzung wäre, könnte ich einfachd
meinen Modul wählen , der normalerweise ausreichend groß ist.Beachten Sie auch, dass Sie diesen Trick nicht mit nur
f(s) = s
(der Identitätsfunktion) ausführen können, da das am weitesten rechts stehende Zeichen der Zeichenfolge im Wesentlichen eine lineare Beziehung (eigentlich eineXOR
Beziehung) zum endgültigen Hash hat (die anderen Zeichen tragen wesentlich nichtlinearer bei) ). Die Wiederholung der Zeichenfolge stellt daher sicher, dass die Unterschiede zwischen den Zeichenfolgen verstärkt werden, um den Effekt zu beseitigen, dass nur das Zeichen ganz rechts geändert wird.1 Das ist offenkundiger Unsinn.
2 Das Hashing von Python-Strings hängt von der Hauptversion (2 vs 3) und der Bit-Qualität (32-Bit vs 64-Bit) ab. Es kommt nicht auf die Plattform AFAIK an.
quelle
hash('YES'*9)
hat34876679
als Faktor, währendhash('NO'*9)
hat34876679+537105043
als Faktor. Aber woher wusstest du, dass537105043
das ein guter Modul ist? dh es hat keine anderen Kollisionen gemacht?Perl,
534940 BytesPrüfung:
Die Hash-Werte für
YES
undNO
sind gleich und es gibt 18279 Zeichenfolgen^[A-Z]{0,3}$
, die bis auf die einzige Kollision fürYES
und kollisionsfrei sindNO
.Ungolfed:
Ältere Version, 49 Bytes
Da der neue Algorithmus etwas anders ist, behalte ich die alte Version.
Prüfung:
Ungolfed:
Bearbeitungen:
"\0"
als Füllbyte spart 4 Bytes im Vergleich zu$"
.quelle
5457241
und woher20047
? Wie berechnen Sie diese Zahlen? Danke im Voraus.YES
in hex ist594553
. 0x594553 = 5850451.NO
in hex ist4e4f
. 0x4e4f = 20047.Python: 63
Eine unglaublich lahme Lösung:
Es funktioniert, indem alphanumerische Zeichenfolgen als Basis-36-Zahlen interpretiert und für alles andere 0 zurückgegeben werden. Es gibt einen expliziten Sonderfall, um nach einem Rückgabewert von 852 (NEIN) zu suchen und stattdessen 44596 (JA) zurückzugeben.
quelle
try:
und die gesamte dritte Zeile. Sie können auch ein paar Bissen speichern, indem Sie jede logische Zeile auf derselben tatsächlichen Zeile durch Semikolons (def h(s):r=int(s,36);return(r,44596)[r==852]
) trennenPure Bash, 29 Bytes (Funktionskörper)
Dabei wird die Eingabezeichenfolge einfach als Zahl zur Basis 36 behandelt und in eine Dezimalzahl konvertiert. Anschließend wird der Sonderfall behandelt
NO
.Ausgabe:
quelle
Ruby, 51 Bytes
Testcode:
Ausgabe :
quelle
Javascript ( ES6 ) 54 Byte
quelle
Java -
9477Abgerollt:
Erzählung - für
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)
habe ich rechtquelle
CJam, 15 Bytes
Funktioniert wie die unten stehende GolfScript-Lösung. Probieren Sie es online aus.
GolfScript, 17 Bytes
Dieser Ansatz baut auf den Antworten von Nneonneo und Ilmari Karonen auf .
Wie es funktioniert
Einen Algorithmus auswählen
Wir beginnen mit
{b base}:h
, dh die Eingabezeichenfolge wird als Basis-b-Zahl betrachtet. Solangeb > 25
,h
ist inyective.Wir erhalten eine Kollision für die Zeichenfolgen "YES" und "NO", wenn wir
h
Folgendes ändern:,{x base n}:h
wobein
ein Teiler von ist"YES" h "NO" h -
.Dies bedeutet leider auch eine Kollision für zB
YET
undNP
. Um dies zu verhindern, müssen wir die Zahl zur Basis b nichtlinear modifizieren, bevor wir den Modul nehmen.Der kürzeste Weg, dies in GolfScript zu erreichen, besteht darin, die Base-B-Zahl mit sich selbst zu multiplizieren (dh zu quadrieren).
h
ist jetzt{base b .* n %}:h
.Es müssen nur noch geeignete Werte für
b
und gefunden werdenn
. Wir können dies mit brachialer Gewalt erreichen:Die kürzest möglichen Werte für
b n
sind:Testen
quelle
JavaScript (ES6) - 38 Zeichen (33 Zeichen Funktionskörper)
Testfälle:
Erläuterung:
Zunächst möchte ich Ihnen
NaN
in JavaScript "Not A Number" vorstellen . Es ist eine Nummer:So wie:
Seine besondere Eigenschaft ist, dass es sich selbst niemals gleicht . Meine Funktion gibt zurück,
1
wenn der StringYES
oder istNO
, undNaN
für jeden anderen String.Dies verstößt also nicht gegen die Regeln, da es für keine andere Zeichenfolge eine Hash-Kollision geben würde;) (
NaN !== NaN
wie oben in Testfällen gezeigt).Und mein Traum wird wahr: Bash, Perl und Ruby in Codelänge schlagen!
Ungolfed Code:
Wenn dieser Wert
"WUVT"
oder ist"Tk8="
, kehren Sie zurück1
. Andernfalls kehren Sie zurückwelches wäre
NaN
.quelle
^\d+$
. Und JS behandeltNaN
als Nummer. Sie können es mit einer Zahl multiplizieren, wie bei Zahlen, addieren, dividieren, subtrahieren. Es ist eine spezielle Eigenschaft von JavaScript. Es schadet nichts, es zu benutzen. Das nennen wir das Biegen von Regeln ;)Object.is()
und behaupten, dass es immer noch eine Kollision ist…==
zum Vergleich den Gleichheitsoperator ( ) verwendet, der sicherstellt, dass außer "YES" oder "NO" keine Hash-Kollision für eine Zeichenfolge auftritt.NaN
nicht als KollisionNA
NP
YEQ
YET
Python 92
Die Hash-Funktion verkettet die Ordinalwerte der ASCII-Zeichen, die print-Anweisung stellt sicher, dass die beiden gewünschten Eingaben kollidieren.
quelle
ECMAScript 6 (30 Byte)
Ich habe versucht, Variablenzuweisung, Rückgabe und Funktionsschlüsselwort zu vermeiden, und dies scheint ein guter Weg zu sein, um all diesen Unsinn zu vermeiden (in gewisser Weise sieht es auch nach funktionaler Programmierung aus). Im Gegensatz zu anderen Lösungen hängt es nicht von
btoa
oder abatob
, das ist nicht ECMAScript 6, sondern HTML5.0+
wird benötigt, damit beliebige Zeichenfolgen analysiert werden können.quelle
a=>parseInt(0+a,36)-852||43744
Java - 45 (oder 62?)
Ich habe keine Ahnung, wie man fair bewertet, wenn man bedenkt, was man braucht, um ein Programm in Java auszuführen. Muss ich die Funktionsdefinition einschließen? Fühlen Sie sich frei, meine Punktzahl entsprechend zu bearbeiten und anzupassen. Momentan erziele ich die gleiche Punktzahl wie die Antwort von @OldCurmudgeon. Addiere 17 für
int h(String t){}
falls erforderlich:Ungolfed mit Testgeschirr:
quelle
Und der Verlierer ist ...
Förderer, 145 Zeichen
Grundsätzlich macht dieses Programm eine Art Basis-26-Sache mit den Zeichen. Danach wird geprüft, ob der Hash 12999 (der Hash-Code von YES) entspricht, und in diesem Fall 404 (der Hash-Code von NO) ausgegeben, andernfalls wird nur der Hash-Code ausgegeben.
Conveyor ist eine von mir erstellte Sprache, die sich derzeit in der Betaphase befindet. Ein Dolmetscher sowie einige Beispiele und Quellcode finden Sie hier: https://github.com/loovjo/Conveyor
quelle
C # 4.5 (112 Bytes)
Arbeitsversion (?) Von undergroundmonorail in C #. Verknüpft die Bytes in der Zeichenfolge zu einer 32-Bit-Ganzzahl (es können nur bis zu 4 Zeichen verwendet werden). Anschließend wird das Ergebnis mit dem Ergebnis für "JA" bzw. "NEIN" verknüpft und anschließend werden diese miteinander verknüpft.
Während es irgendwann kollidieren kann, sollte es nicht für andere ^ [AZ] {2,3} $ als "JA" und "NEIN" passieren.
quelle
Kein Kommentar - 31 (Funktionsinhalt: 26)
Ziemlich einfache Lösung. ;) Funktioniert für alle UTF-8-Strings.
ERLÄUTERUNG:
'
ist natürlich die Funktion. Zuerst wird geprüft, ob*
(seine Eingabe) gleich|,,|+|"#|
(|NO|
) ist. Wenn dies der Fall ist, gibt es zurück|, |+|-%3|
(|YES|
) - andernfalls wird nur zurückgegeben*
.quelle
C 54
Konvertieren Sie den String in eine Ganzzahl - "NO" und multiplizieren Sie diese mit dem gleichen Wert + "NO" - "YES", um 0 für "NO" und "YES" und einen Wert ungleich Null für jeden anderen String im angegebenen Bereich zu erhalten.
Alle Werte auf Windows 7-Computern, wenn Endian-Probleme bestehen.
quelle
Stax ,
1211 BytesFühren Sie es aus und debuggen Sie es
Übersetzt die Eingabe als Basis 36, subtrahiert 852 und ersetzt dann 0 durch 43744. Dies ist eine Portierung von Konrads ausgezeichneter Lösung .
quelle
CoffeeScript - 36
Sollte
1
fürYES
und zurückkehrenNO
, und was auch immer verstümmelter Unsinnatob
für alles andere erzeugt, das keine base64-Zeichenfolge ist.Das JavaScript-Äquivalent ( nicht der JS-Code vom CS-Compiler):
quelle
_
wenn die Eingabe nicht "JA" oder "NEIN" ist.Hier ist eine super lahme. So lahm, dass es nicht einmal funktioniert
Python 2.7 - 79 BytesZuerst erhalten wir die Summe von (ASCII-Wert jedes Zeichens) * 100 ^ (Position dieses Zeichens in der Zeichenfolge). Dann multiplizieren wir (dieses Ergebnis - 7978) und (dieses Ergebnis - 836989), um unsere endgültige Antwort zu erhalten. 7978 und 836989 sind die Ergebnisse für "JA" und "NEIN" des ersten Bits, also multiplizieren wir für JA und NEIN mit 0.
Dies sollte keine Kollisionen haben? Ich habe keine Lust, gegen 18000 mögliche Gegenbeispiele zu testen, aber wenn es eine unbeabsichtigte Kollision gab, kann ich eine weitere 0 darauf werfen,
100
und dann sollte es wirklich keine Kollisionen geben.Enttäuscht, dass ich keinen verwenden konnte
lambda
, aber ich wollte die gesamte Berechnung nicht zweimal durchführen, also musste ich sie in einer Variablen speichern.Bitte lass das nicht gewinnen. Es ist super lahm und ich verdiene es nicht.
quelle