Hash collision: "NO" significa "SÌ"


63

Questo Code Golf è stato ispirato dal recente articolo del Daily WTF You Can't Handle the True! , che presenta un confronto di stringhe scritto come:

String yes = "YES";
if ((delay.hashCode()) == yes.hashCode())

Immagina il problema che avrebbe causato al team di Steve se il String.hashCodemetodo Java fosse stato implementato in quel modo "YES".hashCode() == "NO".hashCode(). Quindi, la sfida che propongo qui è:

Scrivi, nel minor numero di caratteri possibile, una funzione hash (la chiamerò h) con un parametro stringa e un valore di ritorno intero, tale che h("YES")sia uguale a h("NO").

Naturalmente, questo sarebbe banale a che fare con una funzione simile def h(s): return 0, che provoca una collisione hash per ogni stringa. Per rendere questa sfida più interessante, devi rispettare la seguente regola aggiuntiva:

Degli altri 18 277 possibili stringhe composte da tre o meno lettere maiuscole ASCII ( ^[A-Z]{0,3}$), ci deve essere nessun collisioni hash.

Chiarimento (sottolineato da Heiko Oberdiek): la stringa di input può contenere caratteri diversi da A-Ze il codice deve essere in grado di eseguire l'hashing di stringhe arbitrarie. (Tuttavia, è possibile supporre che l'input sia una stringa di caratteri anziché un puntatore null o un oggetto di qualche altro tipo di dati.) Tuttavia, non importa quale sia il valore restituito per le stringhe che non corrispondono ^[A-Z]{0,3}$, purché è un numero intero.

Inoltre, per offuscare l'intento di questa funzione:

Il codice non deve includere nessuna delle lettere "Y", "E", "S", "N" o "O" (maiuscole o minuscole) all'interno dei caratteri letterali o di stringa.

Naturalmente, questa restrizione non si applica alle parole chiave del linguaggio, così else, returnecc vanno bene.


4
In qualche modo non aiuta che possiamo ancora usare i valori numerici ASCII di YESNOper verificare questa specifica eccezione.
Joe Z.

1
Leggendo l'articolo non si può non ricordare il fumetto "per motivi": threewordphrase.com/pardonme.gif
Antonio Ragagnin,

Risposte:


7

GolfScript: 19 caratteri (24 caratteri per la funzione denominata)

26base.2107=59934*+

Questo è il corpo della funzione. L'assegnazione a una funzione denominata hrichiede altri cinque caratteri:

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

(Il punto e virgola finale può essere omesso, se non ti dispiace lasciare una copia del codice in pila.)

Il nucleo della funzione hash è 26base, che calcola la somma (26 n - k · a k ; k = 1 .. n ), dove n è il numero di caratteri nell'input e a k indica il codice ASCII del k -th carattere di input. Per input composti da lettere ASCII maiuscole, questa è una funzione hash senza collisioni. Il resto del codice confronta il risultato con 2107 (il codice hash di NO) e, se sono uguali, aggiunge 59934 per produrre 2701 + 59934 = 62041, il codice hash di YES.

Ad esempio, vedere questa demo online con casi di test.


Come hai provato questo? Ho appena trovato un mucchio di collisioni . Esempio: h('DXP') == h('KK') == 65884.
nneonneo,

(Python equivalente di quello che hai scritto, per i miei scopi di test: lambda w:sum(ord(c)*26**i for i,c in enumerate(reversed(w*9)))%102983)
nneonneo

@nneonneo: Ovviamente, non abbastanza bene. Ho pensato ho generato il set completo di tre lettere o meno ingressi, hash tutti e controllato che l'insieme di hash ha un elemento inferiore alla serie di ingressi. Chiaramente, il mio cablaggio di prova aveva un bug da qualche parte. :-( Tornerò alla versione originale a 19 caratteri fino a / a meno che non riesca a correggere quella più corta.
Ilmari Karonen,

54

Python 2.x a 32 bit (19)

hash(w*9)%537105043

RSA utilizza un modulo semiprime e questo lo rende sicuro, quindi l'utilizzo di uno con il mio algoritmo hash dovrebbe sicuramente renderlo ancora migliore! 1

Questa è una pura funzione matematica, funziona per tutte le stringhe (l'inferno, funziona per qualsiasi oggetto Python lavabile) e non contiene alcun condizionale o involucro speciale! Python a 32 bit in genere può essere chiamato come python-32sulla maggior parte dei sistemi che hanno entrambi installato 2 .

Ho provato questo, e restituisce 18.278 valori diversi per le stringhe maiuscole 18.279 di 3 lettere o meno. L'assegnazione a una funzione richiede 11 byte in più:

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

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

64-bit Python 2.x (19)

hash(w*2)%105706823

Stesso affare di cui sopra.


Per ottenere questi numeri, è stata utilizzata una piccola parte della matematica modulare. Stavo cercando una funzione fe un modulo ntale hash(f('YES')) % n == hash(f('NO')) % n. Ciò equivale a un test che ndivide d = hash(f('YES')) - hash(f('NO')), cioè dobbiamo solo verificare i fattori di dvalori adeguati di n.

L'ideale nè nel quartiere di 20000 ** 2 per ridurre la possibilità di una collisione di paradossi di compleanno. Trovare un adatto nrisulta essere un po 'di tentativi ed errori, giocando con tutti i fattori d(di solito non ce ne sono molti) e le diverse scelte per la funzione f. Si noti tuttavia che la prova e l'errore sono necessari solo perché volevo renderlo il npiù piccolo possibile (per giocare a golf). Se questo non fosse un requisito, potrei semplicemente scegliere dcome mio modulo, che di solito è sufficientemente grande.

Nota anche che non puoi eseguire questo trucco usando solo f(s) = s(la funzione identità) perché il carattere più a destra della stringa ha essenzialmente una relazione lineare (in realtà una XORrelazione) con l'hash finale (gli altri personaggi contribuiscono in un modo molto più non lineare ). La ripetizione della stringa garantisce quindi che le differenze tra le stringhe siano amplificate per eliminare l'effetto di modificare solo il carattere più giusto.


1 Questa è una sciocchezza brevettuale.
2 L' hash delle stringhe di Python dipende dalla versione principale (2 vs 3) e dal testimone (32 bit contro 64 bit). Non dipende dalla piattaforma AFAIK.


Hai il mio voto. : D
cjfaure,

Sfortunatamente, questo non funziona con le versioni recenti di Python a causa della nuova funzionalità di randomizzazione dell'hash.
dan04,

@ dan04: Strano, pensavo di aver specificato che questo era solo per Python 2.x. L'ho modificato di nuovo.
nneonneo,

Posso sapere come hai trovato questi numeri magici? Vedo che hash('YES'*9)ha 34876679come fattore, mentre hash('NO'*9)ha 34876679+537105043come fattore. Ma come sapevi che 537105043era un buon modulo? cioè non ha fatto altre collisioni?
Antonio Ragagnin,

@AntonioRagagnin: aggiunto alla risposta.
nneonneo,

38

Perl, 53 49 40 byte

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

Test:

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

I valori di hash per YESe NOsono gli stessi e ci sono 18279 stringhe ^[A-Z]{0,3}$, che sono libere da collisioni tranne l'unica collisione per YESe 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";

Versione precedente, 49 byte

Poiché il nuovo algoritmo è leggermente diverso, mantengo la vecchia versione.

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

Test:

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".
}

modifiche:

  • L'uso "\0"come byte di riempimento consente di risparmiare 4 byte rispetto a $".

Da dove viene 5457241e 20047da dove vieni? Come calcoli questi numeri? Grazie in anticipo.
AL

@ n.1: YESin esadecimale è 594553. 0x594553 = 5850451. NOin esadecimale è 4e4f. 0x4e4f = 20047.
nneonneo,

7

Python: 63

Una soluzione incredibilmente zoppa:

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

Funziona interpretando le stringhe alfanumeriche come numeri base-36 e restituendo 0 per tutto il resto. C'è un caso speciale esplicito per verificare un valore di ritorno di 852 (NO) e restituire 44596 (SÌ).


3
A meno che non fraintenda: si tratta di code golf, si può presumere che l'input sia accurato. Puoi abbandonare try:e l'intera terza linea. Puoi anche salvare alcuni morsi avendo tutte le linee logiche sulla stessa linea effettiva, separate da punti e virgola ( def h(s):r=int(s,36);return(r,44596)[r==852])
undergroundmonorail

1
@undergroundmonorail: il parametro stringa per la funzione hash non è limitato nella domanda. Per una determinata classe di stringhe (fino a tre lettere maiuscole) esiste una limitazione relativa ai valori di ritorno della funzione hash. Tuttavia, non importa, cosa viene restituito per altre stringhe, se il valore restituito è un numero intero.
Heiko Oberdiek,

3
Mi piace l'indicizzazione booleana del tuo array lì
kratenko,

6

Pure Bash, 29 byte (corpo della funzione)

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

Questo tratta semplicemente la stringa di input come un numero di base 36 e si converte in decimale, quindi si occupa del NOcaso speciale .

Produzione:

$ h A
10
$ h B
11
$ h CAT
15941
$ h NO
44596
$ h SÌ
44596
$ h ZZZ
46655
$

5

Rubino, 51 byte

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

codice di prova:

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
}

produzione :

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));

srotolato:

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

Narrativa - per f(s) = BigInteger(s.getBytes()):

  • f("YES") xor f("NO") = 5835548
  • Così f("YES") xor 5835548 = f("NO")
  • Quindi f("YES") - (f("YES") xor 5835548) = f("NO") - (f("NO") xor 5835548)ho ragione?

Non puoi incorporare il BigInteger?
mafu,

@mafutrct - YES !!! Grazie.
OldCurmudgeon,

5

CJam, 15 byte

q42b_*81991617%

Funziona come la soluzione GolfScript di seguito. Provalo online.


GolfScript, 17 byte

42base.*81991617%

Questo approccio si basa sulle risposte di nneonneo e Ilmari Karonen .

Come funziona

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.

La scelta di un algoritmo

Iniziamo con {b base}:h, cioè, la stringa di input è considerata un numero base-b. Fintanto cheb > 25 , hè inefficace.

Otteniamo una collisione per le stringhe "SÌ" e "NO" se modifichiamo hnel modo seguente:, {x base n}:hdoven è un divisore di "YES" h "NO" h -.

Sfortunatamente, questo significa che avremo anche una collisione per, ad esempio, YET e NP. Per evitare ciò, dobbiamo modificare il numero base-b in modo non lineare prima di prendere il modulo.

Il modo più breve per ottenere questo risultato in GolfScript è moltiplicare il numero base-b con se stesso (ovvero quadrandolo). hè adesso {base b .* n %}:h.

Tutto ciò che resta da fare è trovare valori adeguati per be n. Possiamo farlo con la forza bruta:

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
    }
}

I valori più brevi possibili per b nsono:

37 92176978
42 81991617

analisi

$ 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 caratteri (corpo funzione 33 caratteri)

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

Casi test:

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

Spiegazione:

Prima di tutto, lascia che ti presenti NaN- "Not A Number" - in JavaScript. È un numero:

typeof NaN  // number

Proprio come:

typeof 42   // number

La sua proprietà speciale è che non è mai uguale a se stesso . La mia funzione restituisce 1se la stringa è YESo NO, e NaNper qualsiasi altra stringa.

Quindi, questo non infrange le regole, perché non ci sarebbe alcuna collisione hash per qualsiasi altra stringa;) ( NaN !== NaNmostrato sopra nei casi di test).

E il mio sogno diventa realtà: battere Bash, Perl e Ruby in codice!

Codice Ungolfed:

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

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

Se quel valore è "WUVT"o "Tk8=", restituisce 1. Altrimenti, ritorna

+s // parseInt(s, 10)

quale sarebbe NaN.


2
NaN potrebbe essere un numero, ma non è un "numero intero" in alcun senso della parola.
Paŭlo Ebermann,

2
@ PaŭloEbermann Dal wiki , "Un numero intero è un numero scritto senza un componente frazionario". La domanda non dice esplicitamente che deve essere l'intero ^\d+$. E JS tratta NaNcome un numero. Puoi moltiplicarlo per un numero, aggiungere, dividere, sottrarre come con i numeri. È una proprietà speciale di JavaScript. Non c'è nulla di male nel usarlo. Questo è ciò che chiamiamo flessione delle regole ;)
Gaurang Tandon,

1
Potrei usare Object.is()e sostenere che è ancora una collisione ...
user2428118

1
@ user2428118 Grazie per aver portato Object.is a mia conoscenza. Non l'ho mai saputo. Ma vorrei far notare che l'OP utilizza l'operatore di uguaglianza ( ==) per il confronto, il che garantirà che non si verifichino collisioni di hash per qualsiasi stringa oltre a "SÌ" o "NO".
Gaurang Tandon,

2
Ignorando il fatto che sostenendo NaNnon conta come collisione sembra a buon mercato, questa soluzione ha collisioni con corde NAattraverso NPe YEQattraversoYET
nderscore

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

La funzione di hashing concatena i valori ordinali dei caratteri ASCII, l'istruzione print assicura che i due input desiderati si scontrino.


2

ECMAScript 6 (30 byte)

Ho cercato di evitare l'assegnazione variabile, il ritorno e la parola chiave funzione, e questo sembra un ottimo modo per evitare tutte quelle sciocchezze (sembra anche una programmazione funzionale, in un certo senso). A differenza di altre soluzioni, non dipende da btoao atob, che non è ECMAScript 6, ma HTML5. 0+è necessario, quindi potrebbe analizzare stringhe arbitrarie.

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

1
Bello! Non sapevo che avessero aggiunto altre basi per l'analisi. Puoi tagliare molti byte però. :)a=>parseInt(0+a,36)-852||43744
nderscore,

@nderscore: grazie per il suggerimento. Ha davvero migliorato molto la mia sceneggiatura.
Konrad Borowski,

2

Java - 45 (o 62?)

Non ho idea di come assegnare un punteggio equo dato quello che serve per eseguire un programma in Java, devo includere la definizione della funzione? Sentiti libero di modificare e adattare il mio punteggio in modo appropriato. Attualmente sto segnando allo stesso modo della risposta @OldCurmudgeon. Aggiungi 17 per int h(String t){}se è richiesto:

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

Non rigato con imbracatura di prova:

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

E chi è più libero è ...

Trasportatore, 145 caratteri

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

Fondamentalmente questo programma fa una sorta di cosa base 26 sui caratteri. Dopodiché controlla se l'hash è uguale a 12999 (Il codice hash di SÌ) e in tal caso stampa 404 (il codice hash di NO), altrimenti stampa solo il codice hash.

Conveyor è un linguaggio creato da me che è attualmente in fase beta ma un interprete insieme ad alcuni esempi e codice sorgente può essere trovato qui: https://github.com/loovjo/Conveyor


0

C # 4.5 (112 byte)

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

Versione funzionante (?) Del tentativo di undergroundmonorail, in C #. Concatena i byte nella stringa in un numero intero a 32 bit (funziona solo fino a 4 caratteri), quindi ORs il risultato rispetto al risultato rispettivamente per "YES" e "NO", quindi OR insieme.

Sebbene a un certo punto possa scontrarsi, non dovrebbe succedere per ^ ^ AZ {2,3} $ diverso da "SÌ" e "NO".


La tua funzione hash avrà molte più collisioni. La tua "funzione hash" sta essenzialmente ignorando molti bit nella concatenazione. Tutte le coppie di stringhe che differiscono solo in quei bit avranno lo stesso codice hash.
Paŭlo Ebermann,

0

Nessun commento - 31 (contenuto della funzione: 26)

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

Soluzione abbastanza semplice. ;) Funziona con qualsiasi stringa UTF-8.

SPIEGAZIONE: ' è, ovviamente, la funzione. Innanzitutto, controlla se *(il suo input) è uguale a |,,|+|"#|( |NO|). In tal caso, restituisce |, |+|-%3|( |YES|), altrimenti restituisce semplicemente *.


2
Non ho mai lavorato con No Comment, sarebbe possibile per te spiegare la tua soluzione come spesso accade con le risposte opache Golfscript, J o APL?
Kaya,

@Kaya Oh, sì, scusa, modificherò il post.
cjfaure,

1
Non sono necessarie scuse, ero solo curioso di sapere come funzionava.
Kaya,

0

C 54

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

Converti la stringa in numero intero - "NO" e moltiplica per lo stesso valore + "NO" - "SÌ" per ottenere 0 per "NO" e "SÌ" e diverso da zero per qualsiasi altra stringa nell'intervallo specificato.

Tutti i valori sul computer Windows 7 in caso di dubbi sugli endian.



-1

CoffeeScript - 36

Dovrebbe restituire 1per YESe NO, e qualsiasi cosa assurdata confusa atobproduce per tutto il resto che non è una stringa base64.

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

L'equivalente JavaScript ( non il codice JS dal compilatore CS):

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

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

3
"La funzione dovrebbe avere un valore di ritorno intero" - Suppongo che il tuo ritorni _quando l'input non è "SÌ" o "NO".
Gaurang Tandon,

-1

Eccone uno super zoppo. COSÌ LAME NON FUNZIONA ANCHE

Python 2.7 - 79 byte

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

Per prima cosa otteniamo la somma di (valore ASCII di ciascun personaggio) * 100 ^ (la posizione di quel personaggio nella stringa). Quindi moltiplichiamo (quel risultato - 7978) e (quel risultato - 836989) per ottenere la nostra risposta finale. 7978 e 836989 sono i risultati per "SÌ" e "NO" del primo bit, quindi per SÌ e NO stiamo moltiplicando per 0.

Questo non dovrebbe avere alcuna collisione? Non mi sento come se il test contro 18000 possibili controesempi, ma se ci fosse uno scontro involontario posso gettare un altro 0 su quella 100e poi c'è davvero non dovrebbe essere collisioni.

Deluso dal fatto che non potevo usare a lambdaper questo, ma non volevo fare l'intero calcolo due volte, quindi ho dovuto salvarlo in una variabile.

Per favore, non lasciarlo vincere. È super zoppo e non me lo merito.


Non soddisfa il requisito "nessun'altra collisione": ci sono solo 18012 hash univoci dal set di stringhe 18277 che non dovrebbero avere collisioni.
dan04,

@dan Damn, dammi un secondo
undergroundmonorail

1
@dan Non riesco a farlo funzionare. Forse c'è qualcosa di intrinsecamente sbagliato nell'algoritmo. Non voglio cancellarlo perché qualcun altro potrebbe sapere cosa c'è che non va, ma metterò una nota
undergroundmonorail

Questo funziona per me, h = lambda s: (hash (s) +997192582) * (hash (s) -480644903)
Lucas

come ha definito una funzione hash simile alla tua ma con 99 ** i * int (c, 36)
Lucas
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.