ค้นหา pangrams ที่สั้นที่สุดจากรายการคำ


10

แกรมคือสตริงที่มีทุกตัวอักษรa- zภาษาอังกฤษอักษรกรณีตาย (มันก็โอเคถ้า pangram มีมากกว่าหนึ่งสำเนาของตัวอักษรหรือถ้ามันมีตัวอักษรที่ไม่ใช่ตัวอักษรนอกเหนือจากตัวอักษร)

เขียนโปรแกรมหรือฟังก์ชั่นซึ่งอินพุตเป็นรายการของสตริงและเอาต์พุตหนึ่งหรือมากกว่าหนึ่งสตริงที่มีคุณสมบัติดังต่อไปนี้:

  • สตริงเอาต์พุตแต่ละรายการต้องเป็น pangram
  • แต่ละสตริงเอาต์พุตต้องถูกจัดรูปแบบโดยการต่อหนึ่งสตริงขึ้นไปจากรายการอินพุตคั่นด้วยช่องว่าง
  • แต่ละสตริงเอาต์พุตต้องสั้นที่สุดหรือผูกให้สั้นที่สุดในบรรดาสตริงทั้งหมดที่มีคุณสมบัติเหล่านี้

หลายโปรแกรมจะเลือกที่จะส่งออกเพียงหนึ่งสาย; คุณเพียงแค่ต้องการส่งออกมากกว่าหนึ่งสายถ้าคุณต้องเขียนโค้ดพิเศษเพื่อ จำกัด การส่งออก

คุณอาจคิดว่าอินพุตไม่มีอักขระหรือช่องว่างที่ไม่สามารถพิมพ์ได้และไม่มีคำใดในนั้นเกินกว่า 26 เท่าของลอการิทึมธรรมชาติของความยาวของรายการ) อักขระ (อย่างไรก็ตามคุณไม่สามารถสันนิษฐานได้ว่าอินพุตนั้นไม่มีอะไรนอกจากตัวอักษรหรืออักษรตัวพิมพ์เล็กเท่านั้นเครื่องหมายวรรคตอนและตัวพิมพ์ใหญ่เป็นไปได้ทั้งหมด)

อินพุตและเอาต์พุตสามารถกำหนดในรูปแบบที่เหมาะสม สำหรับการทดสอบโปรแกรมของคุณฉันขอแนะนำให้ใช้สองกรณีทดสอบ: พจนานุกรมคำศัพท์ภาษาอังกฤษ (คอมพิวเตอร์ส่วนใหญ่มีหนึ่งกรณี) และกรณีต่อไปนี้ (ซึ่ง pangram ที่สมบูรณ์แบบ (26 ตัวอักษร) เป็นไปไม่ได้ดังนั้นคุณจะต้องค้นหา มีตัวอักษรซ้ำซ้อน):

abcdefghi
defghijkl
ijklmnop
lmnopqrs
opqrstuvw
rstuvwxyz

คุณควรรวมตัวอย่างผลลัพธ์ของโปรแกรมพร้อมกับการส่งของคุณ (สิ่งนี้อาจแตกต่างกันไปสำหรับคนอื่นเนื่องจากการใช้รายการคำที่แตกต่างกัน)

เงื่อนไขชัยชนะ

นี่เป็น ท้าทายที่ผู้ชนะคือโปรแกรมที่สั้นที่สุด (ไบต์) ที่วิ่งในเวลาพหุนาม (สรุปสำหรับผู้ที่ไม่ทราบความหมาย: ถ้าคุณเพิ่มขนาดของรายการคำสองเท่าโปรแกรมควรช้าลงโดยไม่เกินค่าคงที่อย่างไรก็ตามปัจจัยคงที่ในคำถามอาจมีขนาดใหญ่เท่ากับคุณ เช่น. ตัวอย่างเช่นมันใช้ได้สำหรับการช้าลงสี่เท่าหรือช้ากว่าแปดครั้ง แต่ไม่เล็กลงตามความยาวของรายการคำ; ปัจจัยที่มันจะช้าลงต้องถูก จำกัด )


เมื่อพิจารณาความซับซ้อนเราสามารถใช้ความจริงที่ว่าแต่ละคำมีความยาวไม่เกิน 26 ตัวอักษร? ขนาดตัวอักษรคงที่เป็น 26 หรือไม่?
xnor

ใช่. ฉันวางข้อ จำกัด ดังกล่าวลงในอินพุตที่นั่นเพื่อทำให้ความซับซ้อนในการกำหนด / คำนวณง่ายขึ้น

ฉันคิดว่าสิ่งนี้จะกลายเป็นเรื่องทางเทคนิค หากคุณเพิกเฉยคำที่ป้อนซ้ำมีจำนวนคำที่เป็นไปได้มากที่สุด 27 ^ 26 และอย่างน้อย 2 ^ (27 ^ 26) อาจมีชุดย่อยของคำเหล่านั้นเป็นอินพุตที่เป็นไปได้ นี่มันใหญ่ แต่ก็คงที่ ดังนั้นโปรแกรมใด ๆ ในเซต จำกัด นี้จึงเป็นเวลาคงที่โดยค่าคงที่คือจำนวนขั้นตอนสูงสุดที่ทำผ่านอินพุตที่เป็นไปได้ทั้งหมด
xnor

ฉันไม่ได้พูดว่าไม่มีคำซ้ำซ้อนในอินพุต ฉันเดาว่าคุณสามารถรันโปรแกรมในเวลา "ทางเทคนิค" O (n) โดยการกรองเครื่องหมายวรรคตอนและขจัดข้อมูลซ้ำซ้อนก่อน แต่ (หรือมีแนวโน้มมากขึ้น O (n log n) ซึ่งจะใช้หน่วยความจำน้อยกว่า radix จะซ้ำซ้อน) จากนั้นคุณจะต้องย้อนกลับจากเวอร์ชันที่กรองไปยังรายการคำดั้งเดิม คุณไม่สามารถเรียกร้องเวลาพหุนามที่มีปัญหาได้หากคุณไม่ผ่านขั้นตอนเหล่านั้นทั้งหมด!

ฉันลืมเรื่องที่ไม่ใช่ตัวอักษร เราสามารถสันนิษฐานว่าสิ่งเหล่านี้เป็น ASCII หรืออย่างอื่นภายในขอบเขต จำกัด บางชุดได้หรือไม่? ถ้าเป็นเช่นนั้นฉันคิดว่าอัลกอริทึมใด ๆ ที่เริ่มต้นด้วยการขจัดข้อมูลซ้ำซ้อนสามารถอ้างได้ว่าเป็นพหุนาม
xnor

คำตอบ:


3

Ruby 159 (วนซ้ำ)

ทับทิม 227 220 229 227 221 (แบบเรียกซ้ำ)

โซลูชั่นซ้ำแบบใหม่ (ตามอัลกอริทึมที่อธิบายโดย @Niel):

c={('A'..'Z').to_a=>""}
while l=gets
d=c.clone
c.map{|k,v|j=k-l.upcase.chars
w=v+" "+l.strip
d[j]=w if !c[j]||c[j].size<w.size}
c=d
end
x=c[[]]
p x[1..-1] if x

วิธีแก้ปัญหาแบบเรียกซ้ำ:

W=[]
while l=gets
W<<l.strip
end
I=W.join(" ")+"!!"
C={[]=>""}
def o(r)if C[r]
C[r]
else
b=I
W.map{|x|s=r-x.upcase.chars
if s!=r
c=x+" "+o(s)
b=c if c.size<b.size
end}
C[r]=b
end
end
r=o ('A'..'Z').to_a
p r[0..-2] if r!=I

การวัดไบต์ขึ้นอยู่กับการออกนอก newline ruby 2.3.1p112สุดท้ายในไฟล์ที่ไม่ได้เรื่องที่จะ จำนวนไบต์เพิ่มขึ้นหลังจากแก้ไขข้อผิดพลาดเล็ก ๆ (เพิ่ม.downcase .upcase สำหรับการคำนึงถึงขนาดตัวพิมพ์ตามที่กำหนดโดยคำแถลงปัญหา)

นี่คือรุ่นก่อนหน้าจากก่อนหน้าตัวย่อที่สั้นลงและเช่น:

#!/usr/bin/env ruby

$words = [];

while (line=gets)
  $words << line[0..-2];
end

$impossible = $words.join(" ")+"!!";

$cache = {};

def optimize(remaining)
  return $cache[remaining] if ($cache[remaining]);
  return "" if (remaining == []);

  best = $impossible;

  $words.each{|word|
    remaining2 = remaining - word.chars;
    if (remaining2 != remaining)
      curr = word + " " + optimize(remaining2);
      best = curr if (curr.length < best.length);
    end
  };

  $stderr.puts("optimize(#{remaining.inspect})=#{best.inspect}");

  return $cache[remaining] = best;
end

result = optimize(('a'..'z').to_a);

puts(result[0..-1]);

มันทำงานยังไง? มันเป็นชุดของตัวละครที่ยังคงครอบคลุมและมีคำซ้ำถ้ามันจะลดการเปิดชุด นอกจากนี้ผลลัพธ์ของการเรียกซ้ำจะถูกบันทึกลงในเครื่อง แต่ละเซ็ตย่อยของ 2 ^ 26 สอดคล้องกับรายการตารางบันทึกความจำ แต่ละรายการดังกล่าวคำนวณในเวลาตามสัดส่วนกับขนาดของไฟล์อินพุต ดังนั้นสิ่งทั้งหมดคือO(N)( Nขนาดของไฟล์อินพุต) อยู่ที่ไหนแม้ว่าจะมีค่าคงที่มาก


1

JavaScript (ES6), 249 248 ไบต์อาจเป็นการแข่งขัน

a=>a.map(w=>w.replace(/[a-z]/gi,c=>b|=1<<parseInt(c,36)-9,b=0,l=w.length)&&(m.get(b)||[])[0]<l||m.set(b,[l,w]),m=new Map)&&[...m].map(([b,[l,w]])=>m.forEach(([t,s],e)=>(m.get(e|=b)||[])[0]<=t+l||m.set(e,[t+l+1,s+' '+w])))&&(m.get(-2^-1<<27)||[])[1]

คำอธิบาย: แปลงอาร์เรย์ด้วยการแปลงตัวอักษรเป็น bitmask โดยบันทึกเฉพาะคำที่สั้นที่สุดสำหรับ bitmask แต่ละตัวในแผนที่ จากนั้นวนซ้ำสำเนาของแผนที่เพิ่มแผนที่โดยเพิ่ม bitmask ที่รวมกันถ้าสตริงผลลัพธ์จะสั้นลง ในที่สุดก็กลับสตริงที่บันทึกไว้สำหรับบิตแมปที่สอดคล้องกับ pangram (ส่งคืนundefinedหากไม่มีสตริงดังกล่าวอยู่)


น่าสนใจ คุณช่วยอธิบายเพิ่มเติมเกี่ยวกับวิธีการทำงานและถ้ามีให้โพสต์โค้ดที่ไม่ได้รับการตอบ
DepressedDaniel

1
นี่ควรเป็นรายการที่ถูกต้อง / แข่งขัน ฉันคิดว่านี่ใช้งานได้จริงใน O ( n log n ) จริงๆแล้ว! (แผนที่มีขีด จำกัด ที่ยากมากของรายการ2²⁶และดังนั้นจึงไม่ปรากฏในความซับซ้อนดังนั้นเวลาที่ใช้เพียงอย่างเดียวคือเวลาที่อ่านอินพุต)

ฉันเพิ่งอ่านคำอธิบายอีกครั้งและฉันเข้าใจวิธีการใช้งานได้แล้ว เรียบร้อย +1 ... อืมมันตัดสินใจหยุดพยายามที่จะเพิ่มแผนที่เมื่อพิจารณาคู่หรือไม่? มันควรดำเนินต่อไปจนกว่าจะไม่มีการผ่อนคลาย
DepressedDaniel

@DepressedDaniel สำหรับ bitmask แต่ละรายการที่แยกออกจากรายการคำดั้งเดิมนั้นจะตรวจสอบ pangrams บางส่วนทั้งหมดที่พบมาและการเพิ่มคำนั้นสร้าง pangram ที่สั้นกว่าที่มันรู้จัก bitmask รวมอยู่หรือไม่
Neil

@ ais523 สำหรับอินพุตขนาดใหญ่ (> 1,000 คำ) ดูเหมือนว่าเวลาส่วนใหญ่จะใช้การแลกเปลี่ยน ฉันลองเปลี่ยนจากแผนที่เป็นอาเรย์และมันก็ช้าลง!
Neil

-1

Python 3, 98 , 94 , 92 ไบต์

print([s for s in input().split()if sum([1 for c in range(65,91)if chr(c)in s.upper()])>25])

วนซ้ำผ่านการแทน ASCII ของตัวอักษรและเพิ่ม 1 ในรายการหากพบตัวอักษรในสตริง หากผลรวมของรายการมากกว่า 25 จะมีตัวอักษรทั้งหมดของตัวอักษรและจะถูกพิมพ์


ฉันคิดว่าคุณสามารถลบช่องว่างระหว่างและ(' ') ifนอกจากนี้คุณยังสามารถเปลี่ยนไปord(i) in range(65,91) 91>x>=65นอกจากนี้ความซับซ้อนคืออะไร?
NoOneIsHere

1
ความซับซ้อนของการแก้ปัญหานี้คืออะไร? มันเป็นสิ่งจำเป็นสำหรับคำตอบที่จะต้องมีความซับซ้อนในพหุนามมิฉะนั้นมันไม่ใช่การแข่งขัน
NoOneIsHere

ขออภัยฉันคิดว่ามันเป็น O (n) เพราะรายการอินพุตอาจแตกต่างกันไปตามความยาว แต่
Erich

ขออภัยฉันคิดว่ามันเป็น O (n) เนื่องจากรายการอินพุตสามารถเปลี่ยนแปลงความยาวได้ แต่การวนซ้ำครั้งที่สองจะอยู่ระหว่าง 65 ถึง 90 แต่ฉันยังไม่ได้ทดสอบ
ริช

ไม่แน่ใจว่าสิ่งนี้เป็นไปตาม "สตริงเอาต์พุตแต่ละรายการต้องสั้นที่สุดหรือผูกให้สั้นที่สุดในบรรดาสตริงทั้งหมดที่มีคุณสมบัติเหล่านี้"
DepressedDaniel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.