Кратчайшее Панграмматическое Окно

15

Панграмма - это предложение или выдержка, которая содержит все двадцать шесть букв алфавита, как показано в этом кодовом соревновании по гольфу . Однако панграмматическое окно - это панграмма в виде некоторого сегмента текста, который может заканчиваться или начинаться в середине слова, найденного где-то в более крупной работе. Они естественным образом встречаются повсюду, являясь правильными подмножествами истинных панграмм, поэтому просто проверять, содержит ли что-то панграмматическое окно, было бы скучно, а также это было сделано ранее.

Итак, мы заинтересованы в поиске наименьшего фрагмента текста на основе длины буквы! В кратчайшем возможном коде в байтах, конечно, подойдет тема.

Правила и руководства

  • Получите строку в качестве входных данных и верните строку самого маленького панграмматического окна на входе, если оно есть. Если нет, верните либо Boolean False, либо пустую строку.
  • Является ли строка панограмматическим окном или нет, учитывает регистр и зависит только от 26 букв, а не от любых знаков препинания или цифр или других нечетных символов.
  • Точно так же длина буквы окна панграмматики - это общее количество появлений букв в нем, а не просто число каждого символа. Возвращаемое значение должно быть наименьшим на основе этого количества. В конце концов, мы лингвисты, а не программисты.
  • Вывод панграмматического окна должен, однако, быть точной подстрокой ввода, содержащей те же заглавные буквы и знаки препинания и т. Д.
  • Если имеется несколько кратчайших панграмматических окон одинаковой длины буквы, верните любое из них.

Тестовые случаи

'This isn't a pangram.'
==> False

'Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).'
==> 'Quick-Brown-Fox (the one who jumped over some lazy ig'

'"The five boxing wizards jump quickly." stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" he shouted to the heavens.'
==> 'ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ'
Reecer6
источник
1
Для последнего контрольного примера, почему не The five boxing wizards jump quicklyвозвращается?
Blue
1
Во втором случае разрешено ли пространство, предшествующее Q? Это не добавляет к количеству букв.
Нил
2
@muddyfish Потому что у него 31 буква, а в ожидаемом выводе только 26.
Мартин Эндер
4
Хороший первый вопрос!
Rɪᴋᴇʀ
2
Ага. Нет причин, по которым это не должно быть. Принятие «истинного» минимума в духе вопроса, но это не обязательно.
Reecer6

Ответы:

6

Pyth, 20 16 14 байтов

hol@GNf!-GrT0.:

Объяснение:

             .: - substrings of input()
      f!-GrT0   - filter to ones which contain the alphabet
 ol@GN          - sort by number of alphabetical chars
h               - ^[0]

      f!-GrT0   - filter(lambda T:V, substrings)
          rT0   -    T.lower()
        -G      -   alphabet-^
       !        -  not ^

 o              - sort(^, lambda N:V)
   @GN          -   filter_presence(alphabet, N)
  l             -  len(^)

Попробуй это здесь!

Когда нет правильного решения, программа завершает работу с ошибкой без вывода на стандартный вывод.

синий
источник
Похоже, вы не обновили код в первом блоке кода. Также !-GrT0короче для состояния фильтра, я считаю. Я также думаю, что вам нужно, lчтобы сортировка работала правильно.
FryAmTheEggman
О, я ошибся, я имел в виду ссылку. По вашей ссылке у вас все еще есть l, а без нее вы получите разные результаты . Я считаю, что проблема в повторяющихся письмах, но я не уверен на 100%.
FryAmTheEggman
Так что это имеет значение - и спасибо за оптимизацию!
Blue
2

Рубин, 100 байт

Возвращает ноль, если окно не найдено.

->s{r=0..s.size
(r.map{|i|s[i,r.find{|j|(?a..?z).all?{|c|s[i,j]=~/#{c}/i}}||0]}-['']).min_by &:size}
Значение чернил
источник
2

JavaScript (ES6), 139 138 136 байт

s=>[r=l="",...s].map((_,b,a)=>a.map((c,i)=>i>b&&(t+=c,z=parseInt(c,36))>9&&(v++,n+=!m[z],m[z]=n<26||l&&v>l||(r=t,l=v)),t=m=[],v=n=0))&&r

Сохранено 2 байта благодаря @Neil!

изрезанный

var solution =

s=>
  [r=l="",...s].map((_,b,a)=> // b = index of start of window to check
    a.map((c,i)=>
      i>b&&(
        t+=c,
        z=parseInt(c,36)
      )>9&&(
        v++,
        n+=!m[z],
        m[z]=
          n<26||
          v>l&&l||(
            r=t,
            l=v
          )
      ),
      t=m=[],
      v=n=0
    )
  )
  &&r
<textarea cols="70" rows="6" id="input">Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).</textarea><br /><button onclick="result.textContent=solution(input.value)">Go</button><pre id="result"></pre>

user81655
источник
Вы не можете использовать [r=l="",...s].map((_,b,a)=>?
Нейл
@Neil Спасибо, я всегда забываю о третьем параметре в mapфункции.
user81655
Я думаю, что @ edc65 может справиться с этим, хотя я слил код для его разнесенных подстрок с кодом для его тестера панграмм и получил 134-байтовую функцию.
Нейл
Мой лучший результат - 142
edc65
К сожалению, я не думал сохранить его, и мой компьютер вышел из строя, так что теперь я не знаю, что у меня было; лучшее, что я могу сделать сейчас, это 138 байтов.
Нейл
2

PowerShell v2 +, 218 байт

param($a)$z=@{};(0..($b=$a.length-1)|%{($i=$_)..$b|%{-join$a[$i..$_]}})|%{$y=$_;$j=1;65..90|%{$j*=$y.ToUpper().IndexOf([char]$_)+1};if($j){$z[($y-replace'[^A-Za-z]').Length]=$y}}
($z.GetEnumerator()|sort Name)[0].Value

Да, так что манипулирование подстрокой (никаких встроенных модулей не существует) не является сильной стороной PowerShell ...

Мы берем ввод param($a)и устанавливаем новую пустую хеш-таблицу $z. Это будет наше хранилище потенциальных панграмматических подстрок.

Используя небольшую модификацию моего кода из Exploded Substrings , мы создаем все подстроки ввода. Да, даже односимвольные знаки препинания. Это , а не . ;-)

Все эти подстроки заключены в скобки и переданы в другой цикл с помощью |%{...}. Мы временно установили $yтекущую подстроку, установили вспомогательный счетчик $jи запустили еще один цикл 65..90|%{...}, удобно над кодировками ASCII для заглавных букв. Каждый внутренний цикл мы берем$y делаем его заглавными и вытаскиваем .IndexOfэтот конкретный символ. Так как он вернется, -1если не найден, мы +1перед умножением получим результат $j. Это гарантирует, что если какой-либо один символ не найден, $jбудет равен нулю.

Что именно то, что ifвсе. Если $jне ноль, это означает, что каждая буква была найдена хотя бы один раз в подстроке$y , поэтому нам нужно добавить ее в наш пул кандидатов. Мы делаем это, беря $yи забирая -replaceвсе не-буквы ни с чем, что дает нам длину буквы этой подстроки. Мы используем это как индекс в хеш-таблице $zи храним $yв этом индексе. Это имеет причуду перезаписи подстрок одинаковой длины буквы с той, которая встречается «дальше всего» в исходной строке, но это допускается правилами, поскольку нас интересует только длина буквы.

Наконец, нам нужно разобраться $zи вытащить наименьшее. Мы должны использовать .GetEnumeratorвызов, чтобы отсортировать объекты внутри $z , затем sortте , которые включены Name(т. Е. Индекс длины сверху), выбрать [0]th (т. Е. Самый короткий) и вывести его.Value (т. Е. Подстроку). Если подобная подстрока не подходит, это вызовет ошибку ( Cannot index into a null array), когда она попытается проиндексировать $z, и ничего не выведет, что неверно в PowerShell. (третий тестовый пример ниже имеет явное приведение, [bool]чтобы показать это)

Тестовые случаи

PS C:\Tools\Scripts> .\golfing\shortest-pangrammatic-window.ps1 '"The five boxing wizards jump quickly." stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" he shouted to the heavens.'
ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" 

PS C:\Tools\Scripts> .\golfing\shortest-pangrammatic-window.ps1 'Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).'
Quick-Brown-Fox (the one who jumped over some lazy ig

PS C:\Tools\Scripts> [bool](.\golfing\shortest-pangrammatic-window.ps1 "This isn't a pangram.")
Cannot index into a null array.
At C:\Tools\Scripts\golfing\shortest-pangrammatic-window.ps1:2 char:1
+ ($z.GetEnumerator()|sort Name)[0].Value
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

False
AdmBorkBork
источник
2

Haskell, 180 байт

Это было сложно, но очень весело без импорта.

l=['a'..'z']
u=['A'..'Z']
f&[]=[];f&x=x:f&f x
g#h=(.g).h.g
f x|v<-[y|y<-(tail&)=<<(init&x),and$zipWith((`elem`y)#(||))l u]=last$[]:[z|z<-v,all((length.filter(`elem`l++u))#(<=)$z)v]

Гораздо меньше в гольфе:

lowerCase = ['a'..'z']
upperCase = ['A'..'Z']

f & x = takeWhile (not . null) $ iterate f x

(#) = flip on

subStrings x = (tail &) =<< (init & x)

pangram p = and $ zipWith ((`elem` p) # (||)) lowerCase upperCase

leqLetters x y = (length . filter (`elem` lowerCase ++ upperCase)) # (<=)

fewestLetters xs = [ x | x <- xs, all (leqLetters x) xs]

safeHead [] = ""
safeHead xs = head xs

f x = safeHead . fewestLetters . filter pangram . subStrings

Сюрприз, сюрприз: это действительно медленно.

Майкл Кляйн
источник
2

Oracle SQL 11.2, 461 байт

WITH s AS (SELECT SUBSTR(:1,LEVEL,1)c,LEVEL p FROM DUAL CONNECT BY LEVEL<=LENGTH(:1)),v(s,f,l)AS(SELECT c,p,p FROM s UNION ALL SELECT s||c,f,p FROM v,s WHERE p=l+1),c AS(SELECT CHR(96+LEVEL)c FROM DUAL CONNECT BY LEVEL<27),a AS(SELECT LISTAGG(c)WITHIN GROUP(ORDER BY 1) a FROM c)SELECT MIN(s)KEEP(DENSE_RANK FIRST ORDER BY LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')),0))FROM(SELECT s,f,SUM(SIGN(INSTR(LOWER(s),c)))x FROM v,c GROUP BY s,f),a WHERE x=26;

Un-golfed

WITH s AS (SELECT SUBSTR(:1,LEVEL,1)c,LEVEL p FROM DUAL CONNECT BY LEVEL<=LENGTH(:1))
,v(s,f,l) AS
(
  SELECT c,p,p FROM s
  UNION ALL
  SELECT s||c,f,p FROM v,s WHERE p=l+1 
)
,c AS(SELECT CHR(96+LEVEL)c FROM DUAL CONNECT BY LEVEL<27)
,a AS(SELECT LISTAGG(c)WITHIN GROUP(ORDER BY 1) a FROM c)
SELECT MIN(s)KEEP(DENSE_RANK FIRST ORDER BY LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')),0))
FROM(SELECT s,f,SUM(SIGN(INSTR(LOWER(s),c)))x FROM v,c GROUP BY s,f),a
WHERE x=26

Представление sразделяет ввод в символах, а также возвращает позицию каждого символа.

Рекурсивное представление vвозвращает каждую подстроку входных данных
s - это подстрока
f, позиция первого символа подстроки
l позиция последнего символа, добавленного к текущей подстроке

Представление cвозвращает алфавит, одну букву за раз

Представление aвозвращает алфавит, объединенный в одну строку

SELECT s,f,SUM(SIGN(INSTR(LOWER(s),c))
Возвращает для каждой подстроки число различных присутствующих в ней букв,
INSTRвозвращает pos буквы в подстроке, 0, если ее нет,
SIGNвозвращает 1, если pos> 0, 0, если pos = 0

WHERE x=26
Фильтрует подстроку, содержащую весь алфавит

TRANSLATE(LOWER(s),' '||a,' ')
Удаляет каждое письмо из подстроки

LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')
Длина в буквах это длина подстроки минус длина подстроки без букв

SELECT MIN(s)KEEP(DENSE_RANK FIRST ORDER BY LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')),0))
Сохраняет только подстроку с меньшим количеством букв.
Если их больше одного, первый, отсортированный по возрастанию, сохраняется

школа для водителей
источник
2

Python 3, 171, 167, 163, 157 , 149 байтов.

Сохранено 4 байта благодаря DSM.
Сохранено 8 байт благодаря RootTwo.

lambda x,r=range:min([x[i:j]for i in r(len(x))for j in r(len(x))if{*map(chr,r(65,91))}<={*x[i:j].upper()}]or' ',key=lambda y:sum(map(str.isalpha,y)))

Необходимость сортировки по количеству писем убивает меня.

Тестовые случаи:

assert f("This isn't a pangram.") == ' '
assert f("Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).") == ' Quick-Brown-Fox (the one who jumped over some lazy ig', f("Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).")
assert f('"The five boxing wizards jump quickly." stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" he shouted to the heavens.') == '. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ', f('"The five boxing wizards jump quickly." stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" he shouted to the heavens.')
Морган Трепп
источник
Не думайте, что .upper()это необходимо в ключевой функции.
RootTwo
@RootTwo Ой, да, ты прав. Благодарю.
Морган Трепп
1

PowerShell (v4), 198 156 байт

param($s)
-join(@(1..($y=$s.Length)|%{$w=$_
0..$y|%{(,@($s[$_..($_+$w)]))}}|?{($_-match'[a-z]'|sort -U).Count-eq26}|sort -Pr {($_-match'[a-z]').count})[0])


# Previous 198 byte golf
$a,$b,$c=@(1..($s="$args").Length|%{$w=$_
0..($s.Length-$w)|%{if((($t=$s[$_..($_+$w)]-match'[a-z]')|sort -u).Count-eq26){(,@($t.Length,$_,$w))}}}|sort -pr{$_[0]})[0]
(-join($s[$b..($b+$c)]),'')[!$a]

Тестовые случаи

PS C:\> .\PangramWindow.ps1 "This isn't a pangram."


PS C:\> .\PangramWindow.ps1 'Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).'
Quick-Brown-Fox (the one who jumped over some lazy ig

PS C:\> .\PangramWindow.ps1 '"The five boxing wizards jump quickly." stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" he shouted to the heavens.'
ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!

Безголосое объяснение оригинала

Это вложенная петля грубой силы, которая делает раздвижные окна любых размеров:

.SubString(0, 1) -> slide window over the string
.SubString(0, 2) -> slide window over the string
..
.SubString(0, string.Length) -> slide window over the string

Для каждого окна оно фильтрует только буквы (регистр не учитывает регистр без учета регистра), пропускает оставшиеся символы через уникальный фильтр, проверяет наличие 26 уникальных символов в качестве теста панграммы.

Все окна с панграммами превращаются в триплеты (количество букв, включая дубликаты, начальный индекс, длину окна, включая пунктуацию) , которые сортируются, чтобы найти самое короткое по общему количеству символов, выбирается первое и из этого строится выходная строка. ,

За пределами строки много индексирования, для которого PowerShell с пользой возвращает $ null, а не генерирует исключения.

NB. новый 156-байтовый один - тот же самый подход, но переписан, чтобы использовать конвейер намного больше.

$string = "$args"

# increasing window widths, outer loop
$allPangramWindows =  foreach ($windowWidth in 1..$string.Length) {

    # sliding windows over string, inner loop
    0..($string.Length - $windowWidth) | ForEach {

        # slice window out of string, returns a char array
        $tmp = $string[$_..($_+$windowWidth)]

        # filter the char array to drop not-letters
        $tmp = $tmp -match '[a-z]'

        # Drop duplicate letters
        $tmpNoDupes = $tmp | sort -Unique

        # If we're left with a 26 character array, this is a pangrammatic window. Output
        # a PowerShell-style tuple of count of letters, start index, width.
        if($tmpNoDupes.Count -eq 26){
            (,@($tmp.Length,$_,$windowWidth))
        }
    }
}

# Force the result into an array (to handle no-results), sort it
# by the first element (num of letters in the window, total)
$allPangramWindows = @( $allPangramWindows | sort -Property {$_[0]} )

# take element 0, a window with the fewest letters
$windowCharCount, $windowStart, $WindowEnd = $allPangramWindows[0]

# uses the results to find the original string with punctuation and whitespace
if ($windowLen) {
    $string[$windowStart..($windowStart + $windowLen)] -join ''
}

NB. не уверен, что версия без гольфа работает, потому что я не написал это, тогда игра в гольф, это только для экспозиции.

TessellatingHeckler
источник
0

Haskell, 123 байта

import Data.Lists
import Data.Char
h x=take 1$sortOn((1<$).filter isAlpha)[e|e<-powerslice x,['a'..'z']\\map toLower e==""]

Определяет функцию h , которая возвращает пустой список, если нет панграмматического окна или списка из одного элемента с минимальным окном. Пример использования:

*Main>  h "'The five boxing wizards jump quickly.' stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. 'ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!' he shouted to the heavens."
[". 'ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ"]

Как это устроено:

          [e|e<-powerslice x                  ]  -- for all continuous subsequences
                                                 -- e of the input  
                ,['a'..'z']\\map toLower e==""   -- keep those where the list
                                                 -- difference with all letters is
                                                 -- empty, i.e. every letter appears
                                                 -- at least once
    sortOn((1<$).filter isAlpha)                 -- sort all remaining lists on
                                                 -- their length after removing all
                                                 -- non-letters -> (1<$) see below
take 1                                           -- take the first, i.e. the minimum


calculating the length of a list: we're not interested in the length itself, but
in the relative order of the length. (1<$) replaces each element in a list with
the number 1, e.g. "abc" -> "111", "abcd" -> "1111", etc. Such '1'-strings have
the same order as the length of the original list. One byte saved!
Ними
источник