단어 목록에서 가장 짧은 팬 그램 찾기


10

팬 그램은 모든 문자를 포함하는 문자열입니다 a- z영어 알파벳 대소 문자를 구분하지의. (팬 그램에 하나 이상의 문자 사본이 있거나 문자 외에 문자 이외의 문자가 포함되어 있으면 괜찮습니다.)

입력이 문자열 목록이고 다음 특성을 가진 하나 이상의 문자열을 출력하는 프로그램 또는 함수를 작성하십시오.

  • 각 출력 문자열은 팬 그램이어야합니다.
  • 각 출력 문자열은 입력 목록에서 하나 이상의 문자열을 공백으로 구분하여 연결해야합니다.
  • 이러한 속성을 가진 모든 문자열 중에서 각 출력 문자열이 가장 짧거나 가장 짧아야합니다.

많은 프로그램이 하나의 문자열 만 출력하도록 선택합니다. 출력을 제한하기 위해 추가 코드를 작성해야하는 경우 하나 이상의 문자열 만 출력하려고합니다.

입력에 인쇄 할 수없는 문자 나 공백이없고 입력 된 단어가 (길이의 자연 로그의 26 배)보다 길지 않다고 가정 할 수 있습니다. 그러나 입력에 문자 만 포함하거나 소문자 만 포함한다고 가정하지 않아도됩니다. 문장 부호와 대문자는 모두 가능합니다.

입력 및 출력은 합리적인 형식으로 제공 될 수 있습니다. 프로그램을 테스트하려면 두 가지 테스트 사례를 사용하는 것이 좋습니다. 영어 단어 사전 (대부분의 컴퓨터에는 하나가 있음)과 다음 경우 (완벽한 (26 자) 팬 그램이 불가능하므로 하나를 찾아야합니다. 중복 문자 포함) :

abcdefghi
defghijkl
ijklmnop
lmnopqrs
opqrstuvw
rstuvwxyz

제출 한 내용과 함께 프로그램 출력 샘플을 포함해야합니다. (다른 단어 목록을 사용한 결과 사람들마다 다를 수 있습니다.)

승리 조건

이것은 과제입니다. 승자는 다항식 시간으로 실행되는 가장 짧은 프로그램 (바이트)입니다 . (이것이 무엇을 의미하는지 모르는 사람들을위한 요약 : 단어 목록의 크기를 두 배로 늘리면 프로그램은 상수 요소만큼 느려 져야하지만 문제가되는 상수 요소는 사용자만큼 클 수 있습니다. 예를 들어, 단어 목록의 길이에 의해 4 배 느리거나 8 배 느리지 만 유효하지는 않지만 유효하지 않은 요소는 제한되어야합니다.)


복잡성을 결정할 때 각 단어의 길이가 최대 26 자라는 사실을 사용할 수 있습니까? 알파벳 크기는 26의 상수입니까?
xnor

예. 복잡성을 쉽게 정의 / 계산하기 위해 입력에 부분적으로 제한을 두었습니다.

나는 이것이 기술에 있다고 생각합니다. 반복되는 입력 단어를 무시하면 최대 27 ^ 26 개의 가능한 입력 단어가 있으며 최대 2 ^ (27 ^ 26)의 가능한 하위 세트가 가능한 입력으로 존재합니다. 이것은 거대하지만 일정합니다. 따라서이 유한 세트의 모든 프로그램은 상수 시간이며 상수는 가능한 모든 입력에 대해 수행되는 최대 단계 수입니다.
xnor

입력에 중복 된 단어가 없다고 말하지 않았습니다. 나는 문장 부호를 걸러 내고 입력을 먼저 중복 제거하여 "기술적 인"O (n) 시간에 프로그램을 실행할 수 있다고 생각합니다. 중복 제거). 그런 다음 필터링 된 버전에서 원래 단어 목록으로 돌아 가야합니다. 그러나 실제로 모든 단계를 거치지 않으면 다항식 시간을 주장 할 수 없습니다!

나는 편지가 아닌 것을 잊었다. 이것들이 ASCII이거나 유한 세트 내에 있다고 가정 할 수 있습니까? 그렇다면 중복 제거로 시작하는 알고리즘은 다항식 시간이라고 주장 할 수 있다고 생각합니다.
xnor

답변:


3

루비 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

바이트 측정은 파일에서 마지막 줄 바꿈을 생략하는 것을 기반으로합니다 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]

설명 : 문자를 비트 마스크로 변환하여 배열을 변환하여 맵에서 각 비트 마스크에 대해 가장 짧은 단어 만 저장합니다. 그런 다음 맵 사본을 반복하고 결과 문자열이 더 짧은 경우 결합 된 각 비트 마스크를 추가하여 맵을 확장하십시오. 마지막으로 팬 그램에 해당하는 비트 맵에 저장된 문자열을 반환합니다. ( undefined그런 문자열이 없으면 반환 합니다.)


흥미 롭군 작동 방식에 대해 자세히 설명하고 가능한 경우 ungolfed 코드를 게시 할 수 있습니까?
DepressedDaniel

1
유효하고 경쟁적인 항목이어야합니다. 실제로 이것은 실제로 O ( n log n ) 에서 실행된다고 생각합니다 ! (지도의 하드 제한은 2²⁶ 항목이므로 복잡성에 표시되지 않으므로 입력 시간을 읽는 데 걸리는 시간은 유일합니다.)

방금 설명을 다시 읽고 지금 어떻게 작동하는지 알 수 있습니다. 산뜻한. +1 ... 흠, 언제 쌍을 고려하여 맵 확대를 중단하기로 결정합니까? 이완이 불가능할 때까지 계속 진행해야합니다.
DepressedDaniel

@DepressedDaniel 원래 단어 목록에서 추출 된 각 비트 마스크에 대해 지금까지 찾은 모든 부분 팬 그램을 확인하고 단어를 추가하면 현재 결합 된 비트 마스크에 대해 알고있는 것보다 짧은 팬 그램이 생성되는지 여부를 확인합니다.
Neil

@ ais523 큰 입력 (> 1000 워드)의 경우 대부분의 시간이 스와핑에 소비되는 것 같습니다. Map에서 Array로 전환하려고 시도했는데 속도가 느려졌습니다!
Neil

-1

파이썬 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

입력 목록의 길이는 다를 수 있지만 두 번째 루프는 항상 65에서 90으로 진행되므로 O (n)이라고 생각합니다. 그러나 테스트하지 않았습니다.
Erich

"이러한 속성을 가진 모든 문자열 중에서 각 출력 문자열이 가장 짧거나 가장 짧아야합니다."
DepressedDaniel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.