Bir kelime listesinden en kısa pangramları bulun


10

Bir pangram her harfi içeren bir dizedir a- zİngilizce alfabe, küçük harf duyarsız ait. (Pangram bir harfin birden fazla kopyasını içeriyorsa veya harflere ek olarak harf olmayan karakterler içeriyorsa sorun yoktur.)

Girdi dizelerin bir listesi olan ve aşağıdaki özelliklere sahip bir veya daha fazla dizeyi çıkaran bir program veya işlev yazın:

  • Her çıkış dizesi bir pangram olmalıdır.
  • Her çıkış dizesi, giriş listesinden boşluklarla ayrılmış bir veya daha fazla dizeyi birleştirerek oluşturulmalıdır.
  • Her çıkış dizgisi, bu özelliklere sahip tüm dizeler arasında en kısa veya en kısa için bağlı olmalıdır.

Birçok program yalnızca bir dize çıkarmayı seçecektir; çıktıyı sınırlamak için ek kod yazmak zorunda kalırsanız yalnızca birden fazla dize çıktısını almak istersiniz.

Girdinin yazdırılamaz karakterler veya boşluklar içermediğini ve içindeki hiçbir sözcüğün karakter uzunluğundan (liste uzunluğunun doğal logaritmasının 26 katı) uzun olduğunu varsayabilirsiniz. (Ancak, girdinin harflerden veya yalnızca küçük harflerden başka bir şey içermediğini varsayamazsınız; noktalama işaretleri ve büyük harfler tamamen mümkündür.)

Giriş ve çıkış herhangi bir makul formatta verilebilir. Programınızı test etmek için, iki test vakası kullanmanızı öneririm: İngilizce kelimelerin sözlüğü (çoğu bilgisayarda bir tane vardır) ve aşağıdaki durum (bunun için mükemmel (26 harfli) bir pangramın imkansız olduğu için bir tane bulmanız gerekir yinelenen harfler içeren):

abcdefghi
defghijkl
ijklmnop
lmnopqrs
opqrstuvw
rstuvwxyz

Programınızın çıktısının bir örneğini gönderiminize dahil etmelisiniz. (Bu, farklı kelime listeleri kullanmanın bir sonucu olarak farklı insanlar için farklı olabilir.)

Zafer koşulu

Bu meydan okumadır. Kazanan, polinom zamanında çalışan en kısa programdır (bayt cinsinden) . (Bunun ne anlama geldiğini bilmeyen insanlar için bir özet: kelime listesinin boyutunu iki katına çıkarırsanız, program sabit bir faktörden daha yavaş olmamalıdır. Ancak, söz konusu sabit faktör sizin kadar büyük olabilir Örneğin, dört kat daha yavaş veya sekiz kat daha yavaş olması geçerlidir, ancak kelime listesinin uzunluğuna göre daha küçük olması için geçerli değildir; yavaşlama faktörü sınırlanmalıdır.)


Karmaşıklığı belirlerken, her kelimenin en fazla 26 harf uzunluğunda olduğu gerçeğini kullanabilir miyiz? Alfabe boyutunun 26 sabit olduğunu mu?
xnor

Evet. Karmaşıklığı daha kolay tanımlamak / hesaplamak için girişe bu kısıtlamayı kısmen koydum.

Bence bu bir teknikliğe dönüşüyor. Tekrarlanan giriş sözcüklerini yoksayarsanız, en fazla 27 ^ 26 olası giriş sözcüğü vardır ve bu nedenle olası girişler olarak bunların en fazla 2 ^ (27 ^ 26) olası alt kümesi vardır. Bu çok büyük ama sabit. Dolayısıyla, bu sonlu kümedeki herhangi bir program sabit sürelidir ve sabit tüm olası girişler üzerinde atılan maksimum adım sayısıdır.
xnor

Girişte yinelenen kelimeler yok demedim. Sanırım programı noktalama işaretlerini filtreleyerek ve önce girdiyi tekilleştirerek "teknik" O (n) zamanda çalıştırabilirsiniz (ya da daha büyük olasılıkla O (n günlüğü n), bir sayıdan çok daha az bellek kullanır tekilleştirecek). Ardından, filtrelenmiş sürümden orijinal kelime listesine geri dönmeniz gerekir. Yine de, tüm bu adımları atmadığınız sürece söz konusu polinom zamanını talep edemezsiniz!

Mektup olmayanları unutmuştum. Bunların ASCII olduğunu düşünebilir miyiz, yoksa başka bir şekilde sonlu kümeler içinde mi? Eğer öyleyse, tekilleştirmeyle başlayan herhangi bir algoritmanın polinom zamanı olduğunu iddia edebileceğini düşünüyorum.
xnor

Yanıtlar:


3

Ruby 159 (yinelemeli)

Yakut 227 220 229 227 221 (özyinelemeli)

Yeni yinelemeli çözüm (@Niel tarafından açıklanan algoritmaya dayanarak):

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

Eski özyinelemeli çözüm:

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

Bayt ölçümü, önemli olmayan dosyadaki son satırsonu bırakılmasına dayanır ruby 2.3.1p112. Küçük bir hatayı düzelttikten sonra bayt sayısı arttı (ekleme.downcase .upcase sorun ifadesinin gerektirdiği şekilde büyük / küçük harfe duyarsızlık için).

Tanımlayıcıları kısaltmadan önceki bir sürüm:

#!/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]);

O nasıl çalışır? Temelde hala kapsanan bir karakter kümesini korur ve sadece bir kelimeyi ortaya çıkarılan seti azaltacaksa çağıtır. Ayrıca, özyineleme sonuçları not edilir. Her 2 ^ 26 alt kümesi bir not tablosu girişine karşılık gelir. Bu tür her bir girdi, girdi dosyasının boyutuyla orantılı olarak hesaplanır. Yani her şey O(N)( Ngiriş dosyasının boyutu nerede ), büyük bir sabit olsa da.


1

JavaScript (ES6), 249 248 bayt, muhtemelen rakip

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]

Açıklama: Harfleri bir bit maskesine dönüştürerek diziyi dönüştürür ve bir haritadaki her bit maskesi için en kısa sözcüğü kaydeder. Daha sonra haritanın bir kopyası üzerinde yineleyerek, elde edilen dize daha kısa olacaksa, her bir kombine bit maskesini ekleyerek haritayı büyütün. Son olarak, bir pangrama karşılık gelen bitmap için kaydedilen dizeyi döndürün. ( undefinedBöyle bir dize yoksa döndürür .)


İlginç. Nasıl çalıştığı hakkında daha fazla bilgi verebilir ve eğer varsa, kodlanmamış kodu gönderebilir misiniz?
DepressedDaniel

1
Bu geçerli / rakip bir giriş olmalıdır. Aslında bu aslında O ( n log n ) çalışır ! (Harita 2²⁶'lik bir giriş sınırına sahiptir ve bu nedenle karmaşıklıkta görünmez; bu nedenle harcanan tek zaman girişi okuyan zamandır.)

Açıklamayı tekrar okudum ve şimdi nasıl çalıştığını anladım. Temiz. +1 ... Hmm, çiftleri düşünerek haritayı büyütmeye ne zaman son vermeye karar veriyor? Hiçbir rahatlama mümkün olana kadar devam etmelidir.
DepressedDaniel

@DepressedDaniel Orijinal kelime listesinden çıkarılan her bir bitmask için, şimdiye kadar bulduğu tüm kısmi pangramları ve kelimeyi eklemenin, kombine bitmask için şu anda bildiğinden daha kısa bir pangram oluşturup oluşturmadığını kontrol eder.
Neil

@ ais523 Büyük girişler için (> 1000 kelime), çoğu zaman takas için harcanmış gibi görünür. Bir Haritadan Array'a geçmeyi denedim ve daha da yavaşladı!
Neil

-1

Python 3, 98 , 94 , 92 bayt

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

Alfabenin ASCII gösterimi ile yinelenir ve harf dizede bulunursa listeye 1 ekler. Listenin toplamı 25'ten büyükse, alfabenin tüm harflerini içerir ve yazdırılır.


Bence (' ')ve arasındaki boşluğu kaldırabilirsiniz if. Ayrıca değişebilir ord(i) in range(65,91)için 91>x>=65. Ayrıca, karmaşıklık nedir?
NoOneIsHere

1
Bu çözümün karmaşıklığı nedir? Bu edilir gerekli , aksi takdirde sigara yarışıyor, polinom karmaşıklık olması cevabı için.
NoOneIsHere

Üzgünüz, sanırım O (n), çünkü giriş listesinin uzunluğu değişebilir ama
Erich

Üzgünüz, sanırım O (n), çünkü giriş listesinin uzunluğu değişebilir, ancak ikinci döngü her zaman 65'den 90'a gider. Ama test etmedim.
Erich

Bunun "Her çıktı dizesi, bu özelliklere sahip tüm dizeler arasında en kısa veya en kısa için bağlı olmalıdır" ifadesini karşıladığından emin değilim.
DepressedDaniel
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.