การชนของแฮช:“ ไม่” หมายถึง“ ใช่”


63

กอล์ฟรหัสนี้ได้แรงบันดาลใจจากบทความ WTF รายวันล่าสุดที่คุณไม่สามารถจัดการได้จริง! ซึ่งมีการเปรียบเทียบสตริงที่เขียนเป็น:

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

ลองนึกภาพปัญหามันก็จะทำให้เกิดให้กับทีมของสตีฟถ้าของ Java วิธีการที่เพิ่งเกิดขึ้นจะดำเนินการในลักษณะที่ว่าString.hashCode "YES".hashCode() == "NO".hashCode()ดังนั้นความท้าทายที่ฉันเสนอที่นี่คือ:

เขียนตัวอักษรไม่กี่เท่าที่เป็นไปได้, ฟังก์ชั่นแฮช (ฉันจะเรียกมันว่า h) มีพารามิเตอร์สตริงและจำนวนเต็มค่าตอบแทนดังกล่าวว่า จะมีค่าเท่ากับh("YES")h("NO")

ของหลักสูตรนี้จะเป็นที่น่ารำคาญจะทำอย่างไรกับฟังก์ชั่นเช่น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ฯลฯ จะมีการปรับ


4
เป็นวิธีที่ไม่ช่วยให้เราสามารถใช้ค่า ASCII ที่เป็นตัวเลขYESNOเพื่อตรวจสอบข้อยกเว้นเฉพาะนี้ได้
Joe Z.

1
การอ่านบทความหนึ่งไม่สามารถจดจำการ์ตูน "ด้วยเหตุผล": threewordphrase.com/pardonme.gif
Antonio Ragagnin

คำตอบ:


7

GolfScript: 19 ตัวอักษร (24 ตัวอักษรสำหรับฟังก์ชั่นการตั้งชื่อ)

26base.2107=59934*+

นี่คือเนื้อหาของฟังก์ชัน การกำหนดให้ฟังก์ชันที่มีชื่อhจะใช้เวลาอีกห้าตัวอักษร:

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

(สามารถใช้เครื่องหมายอัฒภาคสุดท้ายได้หากคุณไม่ต้องการทิ้งสำเนาของโค้ดที่วางอยู่บนสแต็ก)

แกนของฟังก์ชันแฮชคือ26baseซึ่งคำนวณผลรวม (26 n - k · a k ; k = 1 .. n ) โดยที่nคือจำนวนอักขระในอินพุตและa kหมายถึงรหัส ASCII ของk -th อักขระอินพุต สำหรับอินพุตที่ประกอบด้วยตัวอักษร ASCII ตัวพิมพ์ใหญ่นี่คือฟังก์ชันแฮชที่ไม่มีการชนกัน ส่วนที่เหลือของรหัสเปรียบเทียบผลให้ 2107 (รหัสกัญชาNO) และถ้าพวกเขากำลังเท่ากับเพิ่ม 59934 ให้ผลผลิต 2,701 + 59,934 = 62,041 YESรหัสกัญชา

ตัวอย่างเช่นผลลัพธ์ดูตัวอย่างออนไลน์พร้อมกรณีทดสอบ


คุณทดสอบสิ่งนี้อย่างไร ฉันเพิ่งพบพวงของการชนกัน ตัวอย่าง: h('DXP') == h('KK') == 65884.
nneonneo

(เทียบเท่าหลามของสิ่งที่คุณเขียนเพื่อการทดสอบของเราlambda w:sum(ord(c)*26**i for i,c in enumerate(reversed(w*9)))%102983)
nneonneo

@neonneo: เห็นได้ชัดว่าไม่ดีพอ ฉันคิดว่าฉันสร้างชุดข้อมูลอินพุตสามตัวอักษรหรือน้อยกว่าเต็มรูปแบบแฮชทั้งหมดและตรวจสอบว่าชุดของแฮชมีองค์ประกอบหนึ่งน้อยกว่าชุดอินพุต เห็นได้ชัดว่าชุดทดสอบของฉันมีจุดบกพร่อง :-( ฉันจะเปลี่ยนกลับไปเป็นเวอร์ชัน 19-char ดั้งเดิมจนกระทั่ง / จนกว่าฉันจะแก้ไขได้สั้นกว่านั้น
Ilmari Karonen

54

Python 32 บิต 2.x (19)

hash(w*9)%537105043

RSA ใช้โมดูลัส semiprime และนั่นทำให้ปลอดภัยดังนั้นการใช้อันเดียวกับอัลกอริธึมแฮชของฉันควรทำให้ดียิ่งขึ้น! 1

นี่คือฟังก์ชั่นคณิตศาสตร์บริสุทธิ์ใช้งานได้กับทุกสตริง (นรกทำงานกับวัตถุ Python ที่แฮชได้) และไม่มีเงื่อนไขหรือการใส่ปลอกพิเศษ! 32 บิตงูใหญ่มักจะเรียกว่าเป็นpython-32ในระบบส่วนใหญ่ที่มีทั้งการติดตั้ง2

ฉันได้ทำการทดสอบแล้วและจะคืนค่าที่แตกต่างกัน 18,278 ค่าสำหรับสตริงตัวพิมพ์ใหญ่ 3 ตัวอักษรหรือน้อยกว่า 18,279 ตัว การกำหนดสิ่งนี้ให้กับฟังก์ชันใช้เวลา 11 ไบต์ขึ้นไป:

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

h('YES') == h('NO') == 188338253และ

Python 64- บิต 2.x (19)

hash(w*2)%105706823

ข้อตกลงเดียวกันข้างต้น


เพื่อให้ได้ตัวเลขเหล่านี้เราใช้คณิตศาสตร์แบบแยกส่วนเล็กน้อย ผมกำลังมองหาฟังก์ชั่นfและโมดูลัสดังกล่าวว่าn hash(f('YES')) % n == hash(f('NO')) % nนี้จะเทียบเท่ากับการทดสอบที่nแบ่งd = hash(f('YES')) - hash(f('NO'))คือเราจะต้องตรวจสอบปัจจัยของค่าที่เหมาะสมdn

อุดมคติnอยู่ในละแวกของ 20,000 ** 2 เพื่อลดโอกาสของการชนกันของวันเกิดขัดแย้ง หาที่เหมาะสมnจะเปิดออกจะเป็นบิตของการทดลองและข้อผิดพลาดการเล่นกับปัจจัยทั้งหมดของd(โดยปกติจะมีไม่มาก) fเลือกและแตกต่างกันสำหรับฟังก์ชั่น โปรดสังเกตว่าการทดลองและข้อผิดพลาดเป็นสิ่งจำเป็นเท่านั้นเพราะฉันต้องการทำให้มีnขนาดเล็กที่สุดเท่าที่จะทำได้ (สำหรับการเล่นกอล์ฟ) ถ้านั่นไม่ใช่ข้อกำหนดฉันก็สามารถเลือกdเป็นโมดูลัสของฉันซึ่งมักจะมีขนาดใหญ่พอ

โปรดทราบด้วยว่าคุณไม่สามารถดึงเคล็ดลับนี้ออกได้โดยใช้เพียงแค่f(s) = s(ฟังก์ชั่นระบุตัวตน) เพราะตัวอักษรที่อยู่ด้านขวาสุดของสตริงนั้นมีความสัมพันธ์เชิงเส้น (จริง ๆ แล้วเป็นXORความสัมพันธ์) ด้วยแฮชสุดท้าย ) การทำซ้ำของสายอักขระจึงทำให้มั่นใจได้ว่าความแตกต่างระหว่างสายอักขระถูกขยายเพื่อกำจัดผลกระทบของการเปลี่ยนแปลงเฉพาะอักขระที่อยู่ด้านขวาสุด


1นี่เป็นเรื่องไร้สาระของสิทธิบัตร
การแฮชสตริงของ Python 2ขึ้นอยู่กับรุ่นหลัก (2 ต่อ 3) และ bitness (32- บิตกับ 64- บิต) ไม่ได้ขึ้นอยู่กับแพลตฟอร์ม AFAIK


คุณได้รับคะแนนของฉัน : D
cjfaure

ขออภัยนี่ไม่สามารถใช้งานได้กับ Python เวอร์ชันล่าสุดเนื่องจากคุณลักษณะการสุ่มแบบแฮชใหม่
dan04

@ dan04: แปลกฉันคิดว่าฉันระบุว่านี่สำหรับ Python 2.x เท่านั้น ฉันแก้ไขมันอีกครั้ง
nneonneo

ฉันขอทราบวิธีที่คุณค้นพบตัวเลขเวทย์มนตร์เหล่านี้ได้ไหม? ผมเห็นhash('YES'*9)มี34876679เป็นปัจจัยในขณะที่hash('NO'*9)มี34876679+537105043เป็นปัจจัย แต่คุณจะรู้537105043ได้อย่างไรว่า มันเป็นโมดูลัสที่ดี? นั่นคือมันไม่ได้ทำให้เกิดการชนอื่น ๆ ?
อันโตนิโอ Ragagnin

@AntonioRagagnin: เพิ่มเข้าไปในคำตอบ
nneonneo

38

Perl, 53 49 40 ไบต์

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

ทดสอบ:

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

ค่าแฮสำหรับYESและNOจะเหมือนกันและมี 18,279 สาย^[A-Z]{0,3}$ซึ่งเป็นชนฟรียกเว้นสำหรับการปะทะกันเฉพาะและYESNO

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

รุ่นเก่ากว่า 49 ไบต์

เนื่องจากอัลกอริทึมใหม่แตกต่างกันเล็กน้อยฉันจึงใช้เวอร์ชั่นเก่า

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

ทดสอบ:

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

การแก้ไข:

  • ใช้"\0"เป็นเติมไบต์ช่วย 4 $"ไบต์ในการเปรียบเทียบกับ

จะอยู่ที่ไหน5457241และ20047มาจากไหน? คุณจะคำนวณตัวเลขเหล่านี้ได้อย่างไร ขอบคุณล่วงหน้า.
อัล

@ n.1: ในฐานสิบหกคือYES 5945530x594553 = 5850451. ในฐานสิบหกคือNO 4e4f0x4e4f = 20047.
nneonneo

7

Python: 63

ทางออกง่อยอย่างไม่น่าเชื่อ:

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

มันทำงานโดยการตีความสตริงตัวอักษรและตัวเลขเป็นตัวเลขฐาน -36 และส่งกลับ 0 สำหรับทุกอย่างอื่น มีกรณีพิเศษที่ชัดเจนในการตรวจสอบค่าตอบแทน 852 (NO) และส่งคืน 44596 (YES) แทน


3
นอกจากว่าฉันเข้าใจผิด: มันเป็นรหัสกอล์ฟคุณได้รับอนุญาตให้สมมติว่าอินพุตนั้นถูกต้อง คุณสามารถคลองtry:และบรรทัดที่สามทั้งหมด นอกจากนี้คุณยังสามารถบันทึกการกัดได้ไม่กี่ครั้งโดยให้ทุกบรรทัดตรรกะอยู่ในบรรทัดเดียวกันโดยคั่นด้วยเครื่องหมายอัฒภาค ( def h(s):r=int(s,36);return(r,44596)[r==852])
undergroundmonorail

1
@undergroundmonorail: พารามิเตอร์สตริงสำหรับฟังก์ชันแฮชไม่ได้ถูก จำกัด ในคำถาม สำหรับคลาสที่แน่นอนของสตริง (มากถึงสามตัวอักษรตัวพิมพ์ใหญ่) มีข้อ จำกัด เกี่ยวกับค่าส่งคืนของฟังก์ชันแฮช อย่างไรก็ตามมันไม่สำคัญว่าอะไรจะถูกส่งกลับสำหรับสตริงอื่น ๆ ถ้าค่าส่งคืนเป็นจำนวนเต็ม
Heiko Oberdiek

3
ฉันชอบการทำดัชนีบูลีนของอาร์เรย์ของคุณที่นั่น
kratenko

6

Pure Bash, 29 ไบต์ (ร่างกายฟังก์ชัน)

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

สิ่งนี้จะถือว่าสตริงอินพุตเป็นหมายเลขฐาน 36 และแปลงเป็นทศนิยมจากนั้นจัดการกับNOกรณีพิเศษ

เอาท์พุท:

$ h
10
$ h B
11
$ h CAT
15941
$ h ไม่
44596
$ h ใช่
44596
$ h ZZZ
46655
$

5

Ruby, 51 ไบต์

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

รหัสการทดสอบ:

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
}

ผลลัพธ์:

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

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


5

Java - 94 77

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

คลี่:

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

เรื่องเล่า - สำหรับ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)ฉันถูกไหม

คุณไม่สามารถแทรก BigInteger ได้หรือไม่
mafu

@mafutrct - ใช่ !!! ขอขอบคุณ.
OldCurmudgeon

5

CJam, 15 ไบต์

q42b_*81991617%

ทำงานเป็นโซลูชัน GolfScript ด้านล่าง ลองออนไลน์


GolfScript ขนาด 17 ไบต์

42base.*81991617%

วิธีการนี้สร้างอยู่กับคำตอบของnneonneoและIlmari Karonen

มันทำงานอย่างไร

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.

การเลือกอัลกอริทึม

เราเริ่มต้นด้วย{b base}:hเช่นสตริงเข้าถือเป็นจำนวนฐาน -b ตราบใดb > 25, hเป็น inyective

เราได้รับการปะทะกันสำหรับสตริง "ใช่" และ "ไม่" ถ้าเราปรับเปลี่ยนhในลักษณะดังต่อไปนี้{x base n}:hที่เป็นตัวหารของn"YES" h "NO" h -

แต่น่าเสียดายที่นี้หมายความว่าเรายังจะได้รับการปะทะกันสำหรับเช่น, และYET NPเพื่อป้องกันสิ่งนี้เราต้องแก้ไขหมายเลขฐานขในรูปแบบที่ไม่ใช่เชิงเส้นก่อนนำโมดูลัสมาใช้

วิธีที่สั้นที่สุดที่จะทำให้สำเร็จใน GolfScript คือการคูณจำนวนฐาน b ด้วยตัวมันเอง (เช่นการยกกำลังสอง) อยู่ในขณะนี้h{base b .* n %}:h

ทั้งหมดที่เหลืออยู่ที่จะทำคือการหาค่าที่เหมาะสมสำหรับการและb nเราสามารถทำได้โดยใช้กำลังดุร้าย:

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

ค่าที่สั้นที่สุดที่เป็นไปได้b nคือ:

37 92176978
42 81991617

การทดสอบ

$ 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 ตัวอักษร (33 อักขระฟังก์ชันถ่าน)

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

กรณีทดสอบ:

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

คำอธิบาย:

ก่อนอื่นให้ฉันแนะนำคุณNaN- "Not A Number" - ใน JavaScript มันเป็นตัวเลข:

typeof NaN  // number

เหมือนกับ:

typeof 42   // number

คุณสมบัติพิเศษของมันคือมันไม่เท่ากับตัวเอง ฟังก์ชั่นของฉันจะส่งกลับ1ถ้าสตริงเป็นYESหรือNOและNaNสำหรับสตริงอื่น ๆ

ดังนั้นสิ่งนี้จะไม่ทำลายกฎเนื่องจากจะไม่มีการชนกันของแฮชสำหรับสตริงอื่นใด) ( NaN !== NaNแสดงไว้ด้านบนในกรณีทดสอบ)

และความฝันของฉันเป็นจริง: การทุบตี Bash, Perl และ Ruby ในโค้ดยาว ๆ !

รหัส Ungolfed:

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

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

ถ้าค่าที่เป็น"WUVT"หรือผลตอบแทน"Tk8=" 1อื่นกลับมา

+s // parseInt(s, 10)

NaNซึ่งจะเป็น


2
NaN อาจเป็นตัวเลข แต่ไม่ใช่ "จำนวนเต็ม" ในแง่ของคำศัพท์
Paŭlo Ebermann

2
@ PaŭloEbermannจากwiki "จำนวนเต็มเป็นตัวเลขที่เขียนโดยไม่มีส่วนประกอบเศษส่วน" ^\d+$คำถามไม่ชัดเจนบอกว่าจำนวนเต็มจะต้องมี และ JS ถือว่าNaNเป็นตัวเลข คุณสามารถคูณมันด้วยตัวเลข, เพิ่ม, หาร, ลบได้เช่นเดียวกับตัวเลข มันเป็นคุณสมบัติพิเศษของ JavaScript ไม่มีอันตรายใด ๆ ในการใช้งาน นั่นคือสิ่งที่เราเรียกกันว่ากฏ ;)
Gaurang Tandon

1
ฉันสามารถใช้Object.is()และอ้างว่ามันยังคงเป็นการชนกันอยู่…
2428118

1
@ user2428118 ขอบคุณที่นำ Object.is มาให้ความรู้ของฉัน ฉันไม่เคยรู้เลย แต่ฉันต้องการให้คุณทราบว่า OP ใช้ตัวดำเนินการความเสมอภาค ( ==) เพื่อเปรียบเทียบซึ่งจะรับประกันว่าจะไม่มีการชนกันของแฮชเกิดขึ้นกับสตริงใด ๆ นอกเหนือจาก "YES" หรือ "ไม่"
Gaurang Tandon

2
การเพิกเฉยต่อข้อเท็จจริงที่ว่าการอ้างสิทธิ์NaNไม่นับว่ามีความขัดแย้ง แต่ราคาถูกโซลูชั่นนี้มีการชนกับสตริงNAตลอดNPและYEQผ่านYET
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

ฟังก์ชัน hashing เชื่อมต่อค่าลำดับของอักขระ ASCII ข้อความสั่งพิมพ์ทำให้แน่ใจว่าอินพุตที่ต้องการสองตัวชนกัน


2

ECMAScript 6 (30 ไบต์)

ฉันพยายามหลีกเลี่ยงการกำหนดตัวแปรการส่งคืนและคำหลักของฟังก์ชันและนี่เป็นวิธีที่ยอดเยี่ยมในการหลีกเลี่ยงเรื่องไร้สาระทั้งหมด ไม่เหมือนกับโซลูชันอื่น ๆ มันไม่ได้ขึ้นอยู่กับbtoaหรือatobซึ่งไม่ใช่ ECMAScript 6 แต่เป็น HTML5 0+เป็นสิ่งจำเป็นดังนั้นจึงสามารถแยกสตริงโดยพลการ

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

1
ดี! ฉันไม่รู้ว่าพวกเขาเพิ่มฐานอื่น ๆ เพื่อแยกวิเคราะห์ คุณสามารถตัดได้หลายไบต์ :)a=>parseInt(0+a,36)-852||43744
nderscore

@nderscore: ขอบคุณสำหรับคำแนะนำ มันทำให้สคริปต์ของฉันดีขึ้นมาก
Konrad Borowski

2

Java - 45 (หรือ 62?)

ฉันไม่ทราบวิธีการให้คะแนนอย่างเป็นธรรมเนื่องจากสิ่งที่จำเป็นสำหรับการเรียกใช้โปรแกรมใน Java ฉันต้องรวมคำจำกัดความของฟังก์ชันหรือไม่ รู้สึกอิสระที่จะแก้ไขและปรับคะแนนของฉันอย่างเหมาะสม ขณะนี้ฉันให้คะแนนแบบเดียวกับคำตอบ @OldCurmudgeon เพิ่ม 17 สำหรับint h(String t){}ถ้าจำเป็น:

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

Ungolfed ด้วยสายรัดทดสอบ:

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

และคนขี้เกียจก็คือ ...

สายพานลำเลียง 145 ตัวอักษร

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

โดยพื้นฐานแล้วโปรแกรมนี้ทำของ 26 ชนิดบนตัวอักษร หลังจากนั้นตรวจสอบว่าแฮชเท่ากับ 12999 (รหัสแฮชของ YES) และถ้าเป็นเช่นนั้นให้พิมพ์ 404 (แฮชโค้ดของ NO) มิฉะนั้นจะพิมพ์รหัสแฮช

Conveyor เป็นภาษาที่สร้างขึ้นโดยฉันซึ่งปัจจุบันอยู่ในช่วงเบต้า แต่มีล่ามพร้อมด้วยตัวอย่างและซอร์สโค้ดอยู่ที่นี่: https://github.com/loovjo/Conveyor


0

C # 4.5 (112 ไบต์)

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

ความพยายามของ undergroundmonorail (?) รุ่นใช้งานได้ใน C # เชื่อมต่อไบต์ในสตริงเป็นจำนวนเต็ม 32 บิต (ใช้งานได้สูงสุด 4 อักขระ) จากนั้น ORs ผลลัพธ์กับผลลัพธ์สำหรับ "YES" และ "NO" ตามลำดับจากนั้น ORs เข้าด้วยกัน

ในขณะที่มันอาจชนกันในบางจุด แต่ก็ไม่ควรเกิดขึ้นกับ ^ [AZ] {2,3} $ นอกเหนือจาก "YES" และ "ไม่"


ฟังก์ชันแฮชของคุณจะมีการชนกันมากมาย "ฟังก์ชั่นแฮช" ของคุณนั้นไม่สนใจบิตจำนวนมากในการต่อข้อมูล คู่สตริงทั้งหมดที่แตกต่างกันในบิตเหล่านั้นจะมีรหัสแฮชเดียวกัน
Paŭlo Ebermann

0

ไม่มีความคิดเห็น - 31 (เนื้อหาฟังก์ชั่น: 26)

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

ทางออกที่ง่ายสวย ;) ใช้งานได้กับสตริง UTF-8 ใด ๆ และทั้งหมด

คำอธิบาย: 'แน่นอนฟังก์ชั่น ก่อนอื่นตรวจสอบว่า*(เป็นอินพุต) เท่ากับ|,,|+|"#|( |NO|) หรือไม่ หากเป็นเช่นนั้นก็จะส่งกลับ|, |+|-%3|( |YES|) - *มิฉะนั้นมันก็จะส่งกลับ


2
ฉันไม่เคยทำงานกับ No Comment เป็นไปได้หรือไม่ที่คุณจะอธิบายวิธีแก้ปัญหาของคุณเช่นมักทำกับคำตอบทึบแสง Golfscript, J หรือ APL?
Kaya

@ Kaya โอ้ใช่แล้วฉันจะแก้ไขโพสต์
cjfaure

1
ไม่จำเป็นต้องขอโทษฉันแค่อยากรู้ว่ามันทำงานอย่างไร
Kaya

0

C 54

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

แปลงสตริงเป็นจำนวนเต็ม - "NO" และคูณด้วยค่าเดียวกัน + "NO" - "YES" เพื่อรับ 0 สำหรับ "NO" และ "YES" และไม่ใช่ศูนย์สำหรับสตริงอื่น ๆ ในช่วงที่ระบุ

ค่าทั้งหมดในเครื่อง Windows 7 หากมีข้อสงสัยเกี่ยวกับ endian



-1

CoffeeScript - 36

ควรกลับ1สำหรับYESและNOและสิ่งไร้สาระที่อ่านไม่ออกatobผลิตสำหรับทุกอย่างอื่นที่ไม่ได้เป็น base64 สตริง

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

JavaScript เทียบเท่า ( ไม่ใช่รหัส JS จากคอมไพเลอร์ CS):

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

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

3
"ฟังก์ชั่นควรมีค่าส่งคืนจำนวนเต็ม" - ฉันสมมติว่าคุณส่งคืน_เมื่ออินพุตไม่ใช่ "YES" หรือ "NO"
Gaurang Tandon

-1

นี่คือหนึ่งง่อยสุด ดังนั้นมันไม่ได้ทำงานอะไรเลย

Python 2.7 - 79 ไบต์

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

ก่อนอื่นเราจะได้รับผลรวมของ (ค่า ascii ของตัวละครแต่ละตัว) * 100 ^ (ตำแหน่งของตัวละครนั้นในสตริง) จากนั้นเราคูณ (ผลลัพธ์นั้น - 7978) และ (ผลลัพธ์นั้น - 836989) เพื่อรับคำตอบสุดท้ายของเรา 7978 และ 836989 เป็นผลลัพธ์สำหรับ "YES" และ "NO" ของบิตแรกดังนั้นสำหรับ YES และ NO เราจะคูณด้วย 0

สิ่งนี้ไม่ควรมีการชนกันหรือ ผมไม่รู้สึกเหมือนการทดสอบกับ 18000 counterexamples ไปได้ แต่ถ้ามีการปะทะกันที่ไม่ได้ตั้งใจฉันสามารถโยนอีก 0 ในที่100แล้วมีจริงๆไม่ควรจะเป็นชนใด ๆ

ผิดหวังที่ฉันไม่สามารถใช้สิ่งlambdaนี้ได้ แต่ฉันไม่ต้องการทำการคำนวณทั้งหมดสองครั้งดังนั้นฉันจึงต้องบันทึกลงในตัวแปร

โปรดอย่าปล่อยให้เรื่องนี้ชนะ มันอ่อนแอมากและฉันไม่สมควรได้รับมัน


ไม่ตรงตามข้อกำหนด "ไม่มีการชนกันอื่น": มีแฮชที่ไม่ซ้ำกันเพียง 18012 ชุดจากชุดสตริง 18277 ที่ไม่ควรมีการชน
dan04

@dan damn ให้ฉันสอง
undergroundmonorail

1
@dan ฉันไม่สามารถทำงานได้ อาจมีบางอย่างผิดปกติกับอัลกอริทึม ฉันไม่ต้องการที่จะลบเพราะคนอื่นอาจรู้ว่ามีอะไรผิดปกติ แต่ฉันจะใส่บันทึก
undergroundmonorail

สิ่งนี้ใช้ได้กับฉัน h = lambda s: (hash (s) +997192582) * (hash (s) -480644903)
Lucas

เช่นเดียวกับการกำหนดฟังก์ชั่นแฮชคล้ายกับของคุณ แต่มี 99 ** i * int (c, 36)
ลูคัส
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.