Эта задача - вывести кратчайший путь к файлу после расширения глобуса.
Что такое ракушка? В большинстве оболочек вы можете использовать *
символ в пути для представления любых символов в позиции. Например, если каталог foo
содержит файлы bar
baz
и asdf
, то foo/b*
развернется до foo/bar foo/baz
.
Теперь предположим, что текущий каталог содержит файл с именем ihavealongname
и ничего больше. Если я хочу сослаться на этот файл, я мог бы напечатать *
, который будет представлять только этот один файл, вместо того, чтобы вводить полное имя.
Если каталог также содержит файл с именем ialsohavealongname
, я не могу сделать *
, так как он будет соответствовать обоим файлам. Я должен сделать, по крайней мере, ih*
.
*
Модель также работает для сравнения каталогов выше файла я ищу. Если есть только две директории foo
и bar
, но foo
содержит только файл baz
и bar
содержит файл asdf
, я могу соответствовать foo/baz
с */baz
. Или, еще более лаконично, */b*
. Если бы bar
было пусто, */*
работало бы.
Ваша задача: учитывая строковый массив путей, которые представляют «текущий каталог», и один целевой путь, выведите кратчайшую возможную строку, которая будет расширена только до этого целевого пути после расширения * s.
Целевой путь может быть взят как его собственная строка, как индекс в массиве путей, как первый элемент в массиве переданных путей, или каким-либо другим удобным способом, который не является жестким кодированием. Спросите в комментариях, если не уверены.
Целевой путь гарантированно присутствует в «текущем каталоге».
Вы можете предположить, что все пути содержат только буквенно-цифровые ASCII (и /
). Вы можете использовать в качестве входных путей корневые (начинаются с /
) или относительные (не начинайте с /
).
Если есть несколько одинаково коротких возможностей, верните одну или все из них.
Это Код-гольф, побеждает наименьшее количество байтов!
Тестовые случаи , благодаря Кевину Круйссену .
источник
*
,?
, и[
т.д.? Возможно, будет проще, если вы просто заявите, что имена файлов и каталогов буквенно-цифровые*
и запустил perl,glob
чтобы получить все имена файлов, которые могут иметь отношение (например,foo/bar/baz
становится*/*/*
). После этого это становится задачей обработки строк. И этот вызов уже достаточно сложен. Я думаю, что этот вызов будет чище, так как «учитывая список буквенно-цифровых (и/
) относительных путей, найдите кратчайший глобус, который соответствует только этому существующему целевому путиa*f
для выбораazzf
изazzf
,azzg
,bzzf
. Расширение по желанию иa*b*c
т.д ..Ответы:
Perl 5 ,
136107102 байтВключает
+2
в себяn0
Дайте список файлов на STDIN. Первый считается целевым файлом
Просто код, не делающий переводы строк буквальными:
Преднамеренно вылетает после печати решения.
Все еще кажется слишком длинным (использование
$a
и1/0
очень неудобно), но это начало и должно быть достаточно эффективным.Попробуйте онлайн!
Как это работает
Программа создает потенциальные глобусы, увеличивая их сзади и вперед, начиная с пустой строки. Он делает это в ширину первого пути, так что первые шарики длины 0 судят (только ``), то длина 1 (например
t
,i
,*
), следующая длина 2 (какfb
,i*
,*g
,**
), следующая длина 3 и так далее до тех пор , найден глобус, который соответствует только первому пути. Тогда это будет самый короткий шар, который решит проблему (могут существовать другие с одинаковой длиной).Глобусы длины
n+1
генерируются из глобусов длиныn
путем добавления каждого символа из списка путей, а также*
перед каждым глобаном длиныn
. Так , например , длина 3 Глобы*i*
будет способствовать длине 4 шариковf*i*
,o*i*
,o*i*
,/*i*
,b*i*
...s*i*
,t*i*
и , наконец**i*
. Обратите внимание, что к каждому символу из списка входных путей добавляется префикс, даже если он появляется несколько раз или вообще не имеет смысла, поскольку приводит к чему-то, что никогда не может совпадать.Выполнение этого наивно приведет к комбинаторному взрыву. Вот почему каждый потенциальный глоб оценивается на предмет его полезности, определяя, в каких точках путей он мог бы соответствовать, если глобус использовался в конце полного глобуса. Я делаю это, вставляя
;
в каждое место, где возможно совпадение. Например, для глобусаt*
я получу строку:Это представляет собой «отличительную силу» шара. Каждый шар, который имеет точно такую же отличительную силу, одинаково хорош. Если вы замените их друг на друга в конце полного шара, все они будут совпадать с одинаковыми путями. Так что вы можете использовать самый короткий.
Поэтому, рассматривая длину
n
шариков, я сначала смотрю на их отличительную силу. Если это было замечено ранее, был еще один шар длинойn
или короче, который уже был рассмотрен и расширен, так что этот шар бессмысленен и обрезается. Это, например, избавит от кандидатов, как,**i*
так как та же самая отличительная сила уже была замечена как*i*
. Это также сокращает невозможных кандидатов, как,f*i*
так как отличительная строка не будет иметь;
и просто быть оригинальным списком путей. Будет принят только самый первый невозможный шар, все остальные будут иметь одинаковую способность различения и будут обрезаны. И даже это первое не будет расширено, так как все расширения все еще невозможны и будут сокращены, когда они будут рассмотрены. Одновременноin*
обрезается иi*
т. Д.Вышеуказанное приводит к очень агрессивному сокращению, и поэтому программа способна обрабатывать сложные случаи за очень короткое время. Однако главная неэффективность заключается в том, что в префиксах глобусов-кандидатов ставятся все возможные символы, а не только те, которые находятся непосредственно перед
;
целевым путем пути отличительной строки. Все добавленные символы, которые не находятся перед a;
, не являются проблемой, поскольку они приводят к невозможному глобу, который будет обрезан, когда он будет рассмотрен, но при этом все равно оставит символы непосредственно перед;
другими путями. Таким образом, в конце концов, программа также создает глобусы, которые смогут соответствовать любой комбинации заданных путей. Он понятия не имеет, что он должен концентрироваться на первом пути.Теперь рассмотрим решение проблемы. В приведенном примере это может быть
*/*er/t
. Это дает следующую отличительную строку:Я распознаю решение по наличию
;
в первой позиции (так, чтобы оно соответствовало первому пути) и отсутствию;
в начале любого другого пути (чтобы другие не совпадали)С объясненным алгоритмом я теперь перехожу к реальной программе:
Глобусы-кандидаты будут в массиве,
@a
который я зациклю, используя переменную,$a
которая содержит глобус, который в данный момент находится на рассмотрении. Вместо того, чтобы*
в глобусе, я, однако, буду использовать,\w*
так что$a
это на самом деле регулярное выражение вместо глобуса. Я собираюсь злоупотреблять странностью цикла perl for, который заключается в том, что вы можете добавлять элементы в зацикленный массив во время выполнения цикла, и эти новые элементы будут выбраны в цикле. Поскольку при генерацииn+1
глобусов длины все глобусы длиныn
уже находятся в массиве,@a
это ширина в первую очередь.Благодаря
-n0
опции (неявный цикл по всему входу) список путей представлен в$_
виде одной большой строки с каждым путем, оканчивающимся новой строкойВнутри у
{ }
нас есть:Ой, я только что уничтожил,
$_
и он мне понадобится для следующего цикла. Так что оберните фактический рабочий код внутриЭто соответствует пустой строке в начале
$_
и позволяет запустить код, чтобы определить, чем он будет заменен. Если я убедлюсь, что этот код оценивается как пустая строка$_
, в конце она останется неизменной, даже если я изменю$_
во времяcode
.Возвращаясь сразу после того, как я заменил
$_
отличительную строку:Это как:
//
в перл есть'defined or
. Это похоже на короткое замыкание,or
когда второй аргумент оценивается, только если первый аргументundef
. И это может быть объединено с заданием, как+=
в некоторых других языках. Так что, если они ключ$_
в хэш%seen
являетсяundef
(это то , что вы получите при обращении к несуществующему элементу) только тогда выполнить выражение и назначить его в качестве значения для ключа$_
. Поэтому, если я уверен,expression
что не возвращает,undef
это в основном означает «вычислять выражение тогда и только тогда, когда мы впервые видим эту конкретную отличительную строку». И поскольку$_
он гарантированно содержит a,\n
фактически безопасно использовать глобальный хеш perl для хранения отличительных строк, поэтому$$_
вместо$seen{$_}
Для
expression
использования I:В основном «Для каждого символа (кроме новой строки) в отличительной строке, а также
*
добавьте его к текущему глобу и вставьте его в массив глобусов-кандидатов». За исключением того, что я использую\w*
для*
получения правильного регулярного выражения (я мог бы использовать''
вместо того,""
чтобы избавиться от одной обратной косой черты, но тогда я не мог запустить свой код из командной строки). Обратите внимание, что это также поднимает;
и добавляет их к кандидатным глобусам, но при последующем тестировании их на восстановленных, у$_
которых нет;
, снова будет невозможный глобус и будет сокращен.Обратите внимание, что
/^;/>/\n;/
значение эквивалентно пустой строке, если решение еще не найдено, поэтому оно будет функционировать как пустая замещающая строка и$_
будет восстановленоисточник
-E
Активирует последний уровень языка. Вам нужен по крайней мере Perl,5.10.0
чтобы иметь возможность использоватьsay
. Так что ставьтеuse 5.10.0;
в шапку раздел и все будет работать. Варианты, чтобы установить уровень языка в любом случае бесплатно, даже если вы не можете сделать это с помощью-E
. На самом деле все варианты считаются бесплатными в настоящее время (так что мне даже не нужно их считатьn0
), но я считаю, что это слишком снисходительно для Perl1/
решение действительно! Мне тоже нужно это помнить ...Java 10,
854824796738728703688655652647624 байтаКакой беспорядок ... Это, конечно, нелегкая задача в Java.
Определенно может быть в гольфе на пару сотен байтов, но я просто рад, что это наконец работает.А я говорил тебе. :)-5 байт благодаря @ceilingcat .
-23 байта при переключении с Java 8 на Java 10
Ввод в виде String-массива путей к файлам (с каталогами в виде отдельных элементов и всеми элементами, содержащими
/
начальные символы) и String с входным путем к файлу для поиска.Объяснение:
Попробуйте онлайн. (Тестовые случаи с
ialsohavealongname
/ihavealongnameaswell
немного сокращены по длине иs.add(x.replaceAll("~+","\\*"));
были заменены{s.remove(x);s.add(x.replaceAll("~+","\\*"));}
на работу через 5-10 секунд на TIO вместо тайм-аута через 60 с.)Дополнительное общее объяснение:
Пример: возьмем
/foo, /foo/bar, /foo/barber, /foo/bar/test, /foo/barber/test, /foo/barber/testing, /foo/barber/coding, /foo/test
как заданные пути к файлам, так иfoo/bar/test
как входной путь к файлу для поиска.1) Я начинаю с разбиения ввода пути к
/
файлу и генерирую все сопоставления файлов этих разделенных слов:2) Затем я генерирую все перестановки с этими словами в том же порядке (повторно применяя
/
между ними и спереди):3) Затем я перебираю элементы в этом списке выше и проверяю, совпадает ли он только с одним путем к файлу во входном массиве путей к файлам. (Я делаю это, проверяя две вещи: одинаковое ли количество косых черт и соответствует ли оно регулярному выражению, в котором каждый
*
заменяется на.*
.)Если это так: оставьте (первое) самое короткое, которое мы возвращаем в конце.
источник
>>>
? Я знаю, что>>
это битовый сдвиг вправо.>>>
действует так же, как>>
. Но для отрицательных целых чисел он изменяет бит четности на 0 (некоторые примеры можно посмотреть здесь, в разделе « >> vs >>> » ).-1>>>1
это просто более короткий вариантInteger.MAX_VALUE
(и1<<31
будетInteger.MIN_VALUE
).