Hash-Kollision: "NEIN" bedeutet "JA"


63

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.hashCodeMethode 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, der h("YES")gleich ist h("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, returnetc. sind in Ordnung.


4
Es hilft nicht weiter, dass wir weiterhin die numerischen ASCII-Werte von verwenden können YESNO, um nach dieser bestimmten Ausnahme zu suchen.
Joe Z.

1
Beim Lesen des Artikels kann man sich nicht an den Comic "aus Gründen" erinnern: threewordphrase.com/pardonme.gif
Antonio Ragagnin

Antworten:


7

GolfScript: 19 Zeichen (24 Zeichen für benannte Funktion)

26base.2107=59934*+

Dies ist der Hauptteil der Funktion. Das Zuweisen zu einer benannten Funktion herfordert fünf weitere Zeichen:

{26base.2107=59934*+}:h;

(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 von NO) und addiert, wenn sie gleich sind, 59934 zu 2701 + 59934 = 62041, dem Hash-Code von YES.

Beispielausgabe siehe diese Online-Demo mit Testfällen.


Wie hast du das getestet? Ich habe gerade ein paar Kollisionen gefunden . Beispiel: h('DXP') == h('KK') == 65884.
Nneonneo

(Python - Äquivalent von dem, was Sie geschrieben haben , für meine Testzwecke: lambda w:sum(ord(c)*26**i for i,c in enumerate(reversed(w*9)))%102983)
nneonneo

@ nneonneo: Offensichtlich nicht gut genug. Ich dachte, ich generiere den vollständigen Satz von Eingaben mit höchstens drei Buchstaben, hasche alle und überprüfe, ob die Hash-Menge ein Element weniger als die Menge der Eingaben enthält. Offensichtlich hatte mein Testgeschirr irgendwo einen Fehler. :-( Ich werde auf die ursprüngliche Version mit 19 Zeichen zurückgreifen, bis / sofern ich die kürzere Version nicht reparieren kann.
Ilmari Karonen

54

32-Bit-Python 2.x (19)

hash(w*9)%537105043

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-32auf 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:

h=lambda w:hash(w*9)%537105043

und h('YES') == h('NO') == 188338253.

64-Bit-Python 2.x (19)

hash(w*2)%105706823

Gleiches Angebot wie oben.


Um diese Zahlen zu erhalten, wurde ein bisschen modulare Mathematik verwendet. Ich suchte nach einer Funktion fund einem nsolchen Modul hash(f('YES')) % n == hash(f('NO')) % n. Dies ist gleichbedeutend mit einem Test, der ndividiert d = hash(f('YES')) - hash(f('NO')), dh wir müssen nur die Faktoren von dauf geeignete Werte von überprüfen n.

Das Ideal nliegt in der Nähe von 20000 ** 2, um die Wahrscheinlichkeit einer Geburtstags-Paradox-Kollision zu verringern. Das Finden einer geeigneten Funktion nerweist sich als Versuch und Irrtum, wenn man mit allen Faktoren d(normalerweise gibt es nicht viele) und verschiedenen Auswahlmöglichkeiten für die Funktion spielt f. Beachten Sie jedoch, dass der Versuch und Irrtum nur erforderlich ist, weil ich nso klein wie möglich machen wollte (zum Golfen). Wenn das keine Voraussetzung wäre, könnte ich einfach dmeinen 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 eine XORBeziehung) 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.


Du hast meine Stimme. : D
cjfaure

Leider funktioniert dies in neueren Versionen von Python aufgrund der neuen Hash-Randomisierungsfunktion nicht.
Dan04

@ dan04: Merkwürdig, ich dachte, ich hätte angegeben, dass dies nur für Python 2.x ist. Ich habe es wieder bearbeitet.
Nneonneo

Darf ich wissen, wie Sie diese magischen Zahlen gefunden haben? Ich sehe hash('YES'*9)hat 34876679als Faktor, während hash('NO'*9)hat 34876679+537105043als Faktor. Aber woher wusstest du, dass 537105043das ein guter Modul ist? dh es hat keine anderen Kollisionen gemacht?
Antonio Ragagnin

@AntonioRagagnin: Fügte das zur Antwort hinzu.
Nneonneo

38

Perl, 53 49 40 Bytes

sub h{hex(unpack H6,pop)-20047||5830404}

Prüfung:

h('YES') = 5830404
h('NO')  = 5830404
Keys:   18279
Values: 18278

Die Hash-Werte für YESund NOsind gleich und es gibt 18279 Zeichenfolgen ^[A-Z]{0,3}$, die bis auf die einzige Kollision für YESund kollisionsfrei sind NO.

Ungolfed:

sub h {
    hex(unpack("H6", pop())) - 20047 || 5830404;
    # The argument is the first and only element in the argument array @_.
    # "pop" gets the argument from array @_ (from the end).
    # The first three bytes of the argument or less, if the argument
    # is shorter, are converted to a hex string, examples:
    #   "YES" -> "594553"
    #   "NO"  -> "4e4f"
    # Then the hex string is converted to a number by function "hex":
    #   0x594553 = 5850451
    #   0x4e4f   =   20047
    # The value for "NO" is subtracted, examples:
    #   case "YES": 5850451 - 20047 = 5830404
    #   case "NO":    20047 - 20047 =       0
    # If the argument is "NO", the subtraction is zero, therefore
    # 5830404 is returned, the result of "YES".
}

# Test
my %cache;
sub addcache ($) {$cache{$_[0]} = h($_[0])}

# Check entries 'YES' and 'NO'
addcache 'YES';
addcache 'NO';
print "h('YES') = $cache{'YES'}\n";
print "h('NO')  = $cache{'NO'}\n";

# Fill cache with all strings /^[A-Z]{0-3}$/
addcache '';
for my $one (A..Z) {
    addcache $one;
    for (A..Z) {
        my $two = "$one$_";
        addcache $two;
        for (A..Z) {
            my $three = "$two$_";
            addcache $three;
        }
    }
}
# Compare number of keys with number of unique values
my $keys = keys %cache;
my %hash;
@hash{values %cache} = 1 x $keys;
$values = keys %hash;
print "Keys:   $keys\n";
print "Values: $values\n";

Ältere Version, 49 Bytes

Da der neue Algorithmus etwas anders ist, behalte ich die alte Version.

sub h{($_=unpack V,pop."\0"x4)==20302?5457241:$_}

Prüfung:

h('YES') = 5457241
h('NO')  = 5457241
Keys:   18279
Values: 18278

Ungolfed:

sub h {
    $_ = unpack('V', pop() . ($" x 4);
        # pop():  gets the argument (we have only one).
        # $" x 4: generates the string "    " (four spaces);
        #   adding the four spaces ensures that the string is long
        #   enough for unpack's template "V".
        # unpack('V', ...): takes the first four bytes as
        #   unsigned long 32-bit integer in little-endian ("VAX") order.
    $_ == 20302 ? 5457241 : $_;
        # If the hash code would be "NO", return the value for "YES".
}

Bearbeitungen:

  • Die Verwendung "\0"als Füllbyte spart 4 Bytes im Vergleich zu $".

Woher 5457241und woher 20047? Wie berechnen Sie diese Zahlen? Danke im Voraus.
AL

@ n.1: YESin hex ist 594553. 0x594553 = 5850451. NOin hex ist 4e4f. 0x4e4f = 20047.
nneonneo

7

Python: 63

Eine unglaublich lahme Lösung:

def h(s):
 try:r=int(s,36)
 except:r=0
 return(r,44596)[r==852]

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.


3
Es sei denn, ich verstehe falsch: Es ist Code-Golf, Sie dürfen davon ausgehen, dass die Eingabe korrekt ist. Sie können Graben 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]) trennen
undergroundmonorail

1
@undergroundmonorail: Der String-Parameter für die Hash-Funktion ist in der Frage nicht eingeschränkt. Für eine bestimmte Klasse von Zeichenfolgen (bis zu drei Großbuchstaben) gibt es eine Einschränkung hinsichtlich der Rückgabewerte der Hash-Funktion. Es spielt jedoch keine Rolle, was für andere Zeichenfolgen zurückgegeben wird, wenn der Rückgabewert eine Ganzzahl ist.
Heiko Oberdiek

3
Ich mag die Boolesche Indizierung Ihres Arrays dort
kratenko

6

Pure Bash, 29 Bytes (Funktionskörper)

h()(echo $[n=36#$1,n-852?n:44596])

Dabei wird die Eingabezeichenfolge einfach als Zahl zur Basis 36 behandelt und in eine Dezimalzahl konvertiert. Anschließend wird der Sonderfall behandelt NO.

Ausgabe:

$ h A
10
$ h B
11
$ h CAT
15941
$ h NEIN
44596
$ h JA
44596
$ h ZZZ
46655
$

5

Ruby, 51 Bytes

h=->s{d=s.unpack('C*').join;d=~/896983|^7879$/?0:d}

Testcode:

h=->s{d=s.unpack('C*').join;d=~/896983|^7879$/?0:d}

puts 'YES : '+h.call('YES').to_s # 0
puts 'NO : '+h.call('NO').to_s # 0
puts 'NOX : '+h.call('NOX').to_s # 787988
puts 'FNO : '+h.call('FNO').to_s # 707879
puts ''

values = Hash[]
n = 0
('A'..'Z').each{|c|
    values[c] = h.call(c)
    ('A'..'Z').each{|c2|
        values[c+c2] = h.call(c+c2)
        ('A'..'Z').each{|c3|
            values[c+c2+c3] = h.call(c+c2+c3)
            n += 1
        }
    }
}
puts 'tested '+n.to_s
duplicate = Hash.new()

values.each{|k, e|
    if duplicate.has_key?(e)
        puts 'duplicate : "'+k+'" = "'+duplicate[e].to_s+'" ('+e.to_s+')'
    else
        duplicate[e] = k
    end
}

Ausgabe :

YES : 0
NO : 0
NOX : 787988
FNO : 707879

tested 17576
duplicate : "YES" = "NO" (0)

5

Javascript ( ES6 ) 54 Byte

f=s=>[x.charCodeAt()for(x of s)].join('')^7879||897296
f('YES'); // 897296
f('NO'); // 897296
f('MAYBE'); // -824036582

5

Java - 94 77

int h=new BigInteger(s.getBytes()).intValue();return Math.abs(h-(h^5835548));

Abgerollt:

int hashCode(String s) {
    int h = new BigInteger(s.getBytes()).intValue();
    return Math.abs(h - (h ^ 5835548));
}

Erzählung - für f(s) = BigInteger(s.getBytes()):

  • f("YES") xor f("NO") = 5835548
  • Damit f("YES") xor 5835548 = f("NO")
  • Also f("YES") - (f("YES") xor 5835548) = f("NO") - (f("NO") xor 5835548)habe ich recht

Können Sie die BigInteger nicht inline?
Mafu

@mafutrct - JA !!! Danke.
OldCurmudgeon

5

CJam, 15 Bytes

q42b_*81991617%

Funktioniert wie die unten stehende GolfScript-Lösung. Probieren Sie es online aus.


GolfScript, 17 Bytes

42base.*81991617%

Dieser Ansatz baut auf den Antworten von Nneonneo und Ilmari Karonen auf .

Wie es funktioniert

42base    # Interpret the input string as a base 42 number.
          # "YES" is [ 89 69 83 ] in ASCII, so it becomes 42 * (42 * 89 + 69) + 83 = 159977.
          # "NO" is [ 78 79 ] in ASCII, so it becomes 42 * 78 + 79 = 3355.
          #
.*        # Square. "YES" becomes 25592640529, "NO" becomes 11256025.
          #
81991617% # "YES" becomes 11256025.

Einen Algorithmus auswählen

Wir beginnen mit {b base}:h, dh die Eingabezeichenfolge wird als Basis-b-Zahl betrachtet. Solange b > 25, hist inyective.

Wir erhalten eine Kollision für die Zeichenfolgen "YES" und "NO", wenn wir hFolgendes ändern:, {x base n}:hwobei nein Teiler von ist "YES" h "NO" h -.

Dies bedeutet leider auch eine Kollision für zB YETundNP . 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). hist jetzt {base b .* n %}:h.

Es müssen nur noch geeignete Werte für bund gefunden werden n. Wir können dies mit brachialer Gewalt erreichen:

for((b=26;b<100;b++)){
    P=($(golfscript <<< "['YES' 'NO']{$b base.*}/-" | factor | cut -d\  -f 2-))

    for n in $(for((i=0;i<2**${#P[@]};i++)){
        for((n=1,j=0;j<${#P[@]};n*=${P[j]}**((i>>j)&1),j++)){ :;};echo $n;} | sort -nu);{
            [[ $n -ge 18277 && $(echo -n '' {A..Z}{,{A..Z}{,{A..Z}}} |
                golfscript <(echo "' '/[{$b base.*$n%}/].&,")) = 18278 ]] &&
            echo $b $n && break
    }
}

Die kürzest möglichen Werte für b nsind:

37 92176978
42 81991617

Testen

$ echo -n '' {A..Z}{,{A..Z}{,{A..Z}}} |
     golfscript <(echo '{42base.*81991617%}:h;" "/{.`"\t"+\h+puts}/') |
     sort -k 2n |
     uniq -Df 1
"NO"    11256025
"YES"   11256025

3

JavaScript (ES6) - 38 Zeichen (33 Zeichen Funktionskörper)

h=s=>(a=btoa(s))=="WUVT"|a=="Tk8="||+s

Testfälle:

var l = console.log;
l(  h("YES")  );                // 1
l(  h("NO")  );                 // 1
l(  h("ABC")  );                // NaN     
l(  h("WIN")  );                // NaN
l(  h("YES") === h("NO")  );    // true
l(  h("ABC") === h("WIN")  );   // false
l(  h("WIN") === h("YES")  );   // false

l(  NaN === NaN  );             // false

Erläuterung:

Zunächst möchte ich Ihnen NaNin JavaScript "Not A Number" vorstellen . Es ist eine Nummer:

typeof NaN  // number

So wie:

typeof 42   // number

Seine besondere Eigenschaft ist, dass es sich selbst niemals gleicht . Meine Funktion gibt zurück, 1wenn der String YESoder ist NO, und NaNfü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 !== NaNwie oben in Testfällen gezeigt).

Und mein Traum wird wahr: Bash, Perl und Ruby in Codelänge schlagen!

Ungolfed Code:

h =  // h is a function 
s => // s = string argument

( ( a = btoa(s) )  ==  "WUVT" | a == "Tk8=" )
        ^-- returns some value stored in `a`

Wenn dieser Wert "WUVT"oder ist "Tk8=", kehren Sie zurück 1. Andernfalls kehren Sie zurück

+s // parseInt(s, 10)

welches wäre NaN.


2
NaN mag eine Zahl sein, aber es ist keine "ganze Zahl" im wahrsten Sinne des Wortes.
Paŭlo Ebermann

2
@ PaŭloEbermann Aus dem Wiki , "Eine Ganzzahl ist eine Zahl , die ohne Bruchkomponente geschrieben wird". Die Frage besagt nicht explizit, dass die ganze Zahl sein muss ^\d+$. Und JS behandelt NaNals 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 ;)
Gaurang Tandon

1
Ich könnte es gebrauchen Object.is()und behaupten, dass es immer noch eine Kollision ist…
user2428118

1
@ user2428118 Danke, dass Sie mir Object.is zur Verfügung gestellt haben. Ich habe es nie gewusst. Ich möchte Sie jedoch darauf hinweisen, dass das OP ==zum Vergleich den Gleichheitsoperator ( ) verwendet, der sicherstellt, dass außer "YES" oder "NO" keine Hash-Kollision für eine Zeichenfolge auftritt.
Gaurang Tandon

2
Ignoriert man die Tatsache, dass Behauptungen NaNnicht als Kollision NANPYEQYET
gewertet werden

2

Python 92

n=int("".join(map(str,map(ord,raw_input()))))    # hashing function
print n if 1+(n**2-904862*n)/7067329057 else-1   # input validation

Die Hash-Funktion verkettet die Ordinalwerte der ASCII-Zeichen, die print-Anweisung stellt sicher, dass die beiden gewünschten Eingaben kollidieren.


2

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 btoaoder ab atob, das ist nicht ECMAScript 6, sondern HTML5. 0+wird benötigt, damit beliebige Zeichenfolgen analysiert werden können.

a=>parseInt(0+a,36)-852||43744

1
Nett! Ich wusste nicht, dass sie andere Grundlagen für parseInt hinzugefügt haben. Sie können jedoch viele Bytes schneiden. :)a=>parseInt(0+a,36)-852||43744
nderscore

@nderscore: Danke für den Vorschlag. Es hat mein Skript sehr verbessert.
Konrad Borowski

2

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ürint h(String t){} falls erforderlich:

int h=t.hashCode();return h*h*3%1607172496;

Ungolfed mit Testgeschirr:

import static org.junit.Assert.*;

import java.util.*;

import org.junit.Test;

public class YesNo {
  @Test
  public void testHashValue() {
    YesNo yesNo = new YesNo();
    Set<Integer> set = new HashSet<>();

    assertEquals(yesNo.hash("YES"), yesNo.hash("NO"));

    set.add(yesNo.hash(""));
    for(char i = 'A'; i <= 'Z'; i++) {
      set.add(yesNo.hash("" + i));
      for(char j = 'A'; j <= 'Z'; j++) {
        set.add(yesNo.hash("" + i + j));
        for(char k = 'A'; k <= 'Z'; k++) {
          set.add(yesNo.hash("" + i + j + k));
        }
      }
    }
    assertEquals(18278, set.size());
  }

  int hash(String toHash) {
    int hashValue=toHash.hashCode();
    return hashValue*hashValue*3%1607172496;
  }
}

1

Und der Verlierer ist ...

Förderer, 145 Zeichen

 I
>#<
 26*)2**\88
 >========*
 ^    \ \+-
 ^=====#==<
5**222P:
5======<
5***26*)*(\P\:@e25*:*)4*,F
>==============#=========
             P,F

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


0

C # 4.5 (112 Bytes)

int h(string s){int code=s.Select((v,i)=>((int)v)<<(2*(i-1))).Sum();return(code|1073742225)|(code|-2147483569);}

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.


Ihre Hash-Funktion wird viel mehr Kollisionen haben. Ihre "Hash-Funktion" ignoriert im Wesentlichen viele Bits in der Verkettung. Alle Zeichenfolgenpaare, die sich nur in diesen Bits unterscheiden, haben denselben Hash-Code.
Paŭlo Ebermann

0

Kein Kommentar - 31 (Funktionsinhalt: 26)

'=|*==|,,|+|"#|[|,  |+|-%3|]*|:

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 *.


2
Ich habe noch nie mit No Comment gearbeitet. Wäre es Ihnen möglich, Ihre Lösung zu erläutern, wie dies häufig bei undurchsichtigen Golfscript-, J- oder APL-Antworten der Fall ist?
Kaya

@Kaya Oh ja, sorry, ich werde den Beitrag bearbeiten.
cjfaure

1
Keine Entschuldigung nötig, ich war nur neugierig, wie es funktioniert.
Kaya

0

C 54

h(char *c){int d=*(int*)c-20302;return d*(d-5436939);}

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.



-1

CoffeeScript - 36

Sollte 1für YESund zurückkehren NO, und was auch immer verstümmelter Unsinn atobfür alles andere erzeugt, das keine base64-Zeichenfolge ist.

h=(s)->_=atob s;_ in["`D","4"]&&1||_

Das JavaScript-Äquivalent ( nicht der JS-Code vom CS-Compiler):

function h( s ) {
    var _ = atob( s );

    if( _ === "`D" || _ === "4" )
        return 1;
    else
        return _;
}

3
"Die Funktion sollte einen ganzzahligen Rückgabewert haben" - Ich nehme an, Ihre gibt den zurück, _wenn die Eingabe nicht "JA" oder "NEIN" ist.
Gaurang Tandon

-1

Hier ist eine super lahme. So lahm, dass es nicht einmal funktioniert

Python 2.7 - 79 Bytes

def h(s):n=sum(100**i*ord(c)for i,c in enumerate(s));return (n-7978)*(n-836989)

Zuerst 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, 100und 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.


Erfüllt nicht die Anforderung "Keine anderen Kollisionen": Es gibt nur 18012 eindeutige Hashes aus dem 18277-String-Set, die keine Kollisionen aufweisen sollten.
Dan04

@dan Verdammt, gib mir eine Sekunde
Undergroundmonorail

1
@dan Ich kann es nicht zum Laufen bringen. Möglicherweise stimmt etwas nicht mit dem Algorithmus. Ich möchte es nicht löschen, weil jemand anderes vielleicht weiß, was los ist, aber ich werde eine Notiz anbringen
Undergroundmonorail

Dies funktioniert für mich, h = Lambda s: (Hash (s) +997192582) * (Hash (s) -480644903)
Lucas

ebenso wie das Definieren einer Hash-Funktion, die Ihrer ähnlich ist, aber mit 99 ** i * int (c, 36)
Lucas
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.