To zadanie polega na wyświetleniu najkrótszej ścieżki do pliku po rozszerzeniu globalnym.
Co to jest globbing powłoki? W większości pocisków możesz użyć *
znaku na ścieżce, aby reprezentować dowolne znaki na danej pozycji. Na przykład, jeśli katalog foo
zawiera pliki bar
baz
i asdf
, a następnie foo/b*
wzrośnie do foo/bar foo/baz
.
Załóżmy teraz, że bieżący katalog zawiera plik o nazwie ihavealongname
i nic więcej. Jeśli chcę odwołać się do tego pliku, mógłbym wpisać *
, co będzie reprezentowało tylko ten jeden plik, zamiast wpisywać pełną nazwę.
Jeśli katalog zawiera również plik o nazwie ialsohavealongname
, nie mogę tego zrobić *
, ponieważ będzie pasował do obu plików. Musiałbym przynajmniej zrobić ih*
.
*
Wzór działa również na dopasowanie katalogów powyżej pliku szukam. Jeśli istnieją tylko dwa katalogi foo
i bar
, ale foo
zawiera tylko plik baz
i bar
zawiera plik asdf
, mogę dopasować foo/baz
się */baz
. Lub jeszcze bardziej zwięźle */b*
. Gdyby bar
był pusty, */*
działałby.
Twoje zadanie: Biorąc pod uwagę tablicę łańcuchów ścieżek reprezentujących „bieżący katalog” i jedną ścieżkę docelową, wypisz możliwie najkrótszy ciąg, który rozwinąłby się tylko do tej ścieżki docelowej po rozwinięciu * s.
Ścieżkę docelową można traktować jako własny ciąg znaków, jako indeks do tablicy ścieżek, jako pierwszy element w przekazanej tablicy ścieżek lub w inny wygodny sposób, który nie jest sztywno kodowany. Zapytaj w komentarzach, jeśli nie jesteś pewien.
Gwarantowana ścieżka docelowa znajduje się w „bieżącym katalogu”.
Możesz założyć, że wszystkie ścieżki zawierają tylko alfanumeryczne znaki ASCII (i /
). Możesz przyjąć jako ścieżki wejściowe, które są zrootowane (zacznij od /
) lub względne (nie zaczynaj od /
).
Jeśli istnieje wiele równie krótkich możliwości, zwróć jedną lub wszystkie z nich.
To jest golf-golf, najmniej bajtów wygrywa!
Przypadki testowe , dzięki Kevin Cruijssen .
źródło
*
,?
,[
etc? Być może najłatwiej byłoby po prostu stwierdzić, że nazwy plików i katalogów są alfanumeryczne*
i uruchomiłem perla,glob
aby uzyskać wszystkie nazwy plików, które mogą być istotne (np.foo/bar/baz
stają się*/*/*
). Następnie staje się wyzwaniem przetwarzania łańcucha. To wyzwanie jest już wystarczająco trudne. Myślę, że to wyzwanie byłoby czystsze, ponieważ „biorąc pod uwagę listę alfanumerycznych (i/
) ścieżek względnych, znajdź najkrótszą glob, która pasuje tylko do tej istniejącej ścieżki doceloweja*f
, aby wybraćazzf
zazzf
,azzg
,bzzf
. Przedłuż do wolia*b*c
itp.Odpowiedzi:
Perl 5 ,
136107102 bajtówObejmuje
+2
dlan0
Podaj listę plików na STDIN. Zakłada się, że pierwszy jest plikiem docelowym
Tylko kod bez dosłowności nowego wiersza:
Celowo ulega awarii po wydrukowaniu rozwiązania.
Nadal wydaje się zbyt długi (użycie
$a
i1/0
jest bardzo niewygodny), ale jest to początek i powinien być dość wydajny.Wypróbuj online!
Jak to działa
Program buduje globusy kandydujące, rozwijając je od tyłu do przodu, zaczynając od pustego łańcucha. Czyni to w szerokości pierwszej okazji, więc najpierw globs o długości 0 są sprawdzane (tylko ``), a następnie długość 1 (jak
t
,i
,*
), obok długość 2 (jakfb
,i*
,*g
,**
), obok długość 3 i tak dalej, aż do znaleziono glob, który pasuje tylko do pierwszej ścieżki. Będzie to wtedy najkrótsza kula ziemska, która rozwiązuje problem (mogą istnieć inne o tej samej długości).Globs długości
n+1
są generowane zn
globusów długości , poprzedzając każdy znak z listy ścieżek, a także*
przed każdym globusem długościn
. Tak np długość 3 glob*i*
przyczyni Length 4 globsf*i*
,o*i*
,o*i*
,/*i*
,b*i*
...s*i*
,t*i*
a na końcu**i*
. Zauważ, że każdy znak z listy ścieżek wejściowych jest poprzedzany, nawet jeśli pojawia się wiele razy lub nie ma żadnego sensu, ponieważ prowadzi do czegoś, co nigdy nie może się równać.Robienie tego naiwnie prowadziłoby do eksplozji kombinatorycznej. Dlatego każda kandydująca glob jest oceniana pod kątem przydatności, określając, w których punktach ścieżek mogłaby pasować, gdyby glob był używany na końcu pełnego globu. Robię to, wstawiając znak
;
w każdym miejscu, w którym możliwe jest dopasowanie. Na przykład dla globut*
otrzymam ciąg:To reprezentuje „siłę odróżniającą” globu. Każdy glob, który ma dokładnie taką samą moc odróżniającą, jest równie dobry. Jeśli je zastąpisz na końcu pełnego globu, wszystkie będą pasować dokładnie tymi samymi ścieżkami. Możesz więc równie dobrze użyć najkrótszego.
Rozważając
n
globusy długości , najpierw spoglądam na jego siłę odróżniającą. Jeśli było to widziane wcześniej, istniała kolejna kula długościn
lub krótsza, która była już rozważana i rozszerzana, więc ta kula jest bezcelowa i zostaje przycięta. Pozwoli to na przykład pozbyć się kandydatów,**i*
ponieważ ta sama siła wyróżniająca będzie już postrzegana jako*i*
. Przycina również niemożliwych kandydatów,f*i*
ponieważ ciąg wyróżniający nie będzie miał;
i po prostu być oryginalną listą ścieżek. Tylko pierwszy niemożliwy glob zostanie zaakceptowany, wszystkie pozostałe będą miały tę samą moc odróżniającą i zostaną przycięte. I nawet ten pierwszy tak naprawdę nie zostanie rozszerzony, ponieważ wszystkie rozszerzenia są nadal niemożliwe i zostaną uwzględnione, jeśli zostaną wzięte pod uwagę. Jednocześniein*
będzie przycinany przezi*
itp.Powyższe prowadzi do bardzo agresywnego przycinania, dlatego program jest w stanie obsłużyć złożone przypadki w bardzo krótkim czasie. Główną nieefektywnością jest jednak to, że poprzedza globusy kandydujące wszystkimi możliwymi znakami, nie tylko tymi znajdującymi się tuż przed
;
częścią ścieżki docelowej łańcucha wyróżniającego. Wszystkie dodane postacie, które nie znajdują się przed,;
nie stanowią problemu, ponieważ prowadzą do niemożliwego globu, który zostanie przycięty, gdy zostanie rozpatrzony, ale nadal pozostawia postacie tuż przed;
innymi ścieżkami. Na koniec program buduje globusy, które będą w stanie dopasować dowolną kombinację podanych ścieżek. Nie ma pojęcia, że powinien koncentrować się na pierwszej ścieżce.Teraz rozważ rozwiązanie problemu. W podanym przykładzie może to być
*/*er/t
. Daje to następujący ciąg wyróżniający:Rozpoznaję rozwiązanie, mając pozycję
;
na pierwszej pozycji (więc pasuje do pierwszej ścieżki) i nie mając;
na początku żadnej innej ścieżki (więc inne nie pasują)Po wyjaśnieniu algorytmu przechodzę teraz do właściwego programu:
Kandydujące globusy będą w tablicy,
@a
którą zapętlę, używając zmiennej$a
zawierającej aktualnie rozpatrywaną glob. Zamiast*
globu użyję jednak,\w*
więc$a
jest to regex zamiast globu. Mam zamiar nadużyć dziwnego charakteru perla dla pętli, że można dodawać elementy do tablicy zapętlonej podczas działania pętli, a te nowe elementy zostaną przechwycone w pętli. Ponieważ podczas generowanian+1
globów długości wszystkie globusy długościn
są już w tablicy,@a
jest to szerokość pierwsza.Ze względu na
-n0
opcję (niejawna pętla nad całym wejściem) lista ścieżek jest w$_
postaci jednego dużego łańcucha z każdą ścieżką zakończoną znakiem nowej liniiWewnątrz
{ }
mamy:Ups, właśnie zniszczyłem
$_
i będę go potrzebował do następnej pętli. Więc zawiń rzeczywisty działający kodOdpowiada to pustemu ciągowi na początku
$_
i umożliwia uruchomienie kodu w celu ustalenia, co zostanie zastąpione. Jeśli upewnię się, że kod oceniany na pusty ciąg znaków$_
na końcu pozostanie niezmieniony, nawet jeśli zmienię$_
podczascode
.Wracając do zaraz po tym, jak zastąpiłem
$_
ciąg wyróżniający:To jest jak:
//
w perlu jest'defined or
. To jest jak zwarcie, wor
którym drugi argument jest oceniany tylko wtedy, gdy jest pierwszyundef
. I można to połączyć z zadaniem, tak jak+=
w niektórych innych językach. Więc jeśli klucz$_
w hash%seen
jestundef
(co jest to co masz przy dostępie do nieistniejącego elementu) dopiero wtedy wykonać ekspresję i przypisać ją jako wartość dla klucza$_
. Więc jeśli upewnię się,expression
że nie zwróciundef
, oznacza to w zasadzie „oceń wyrażenie wtedy i tylko wtedy, gdy po raz pierwszy zobaczymy ten szczególny ciąg wyróżniający”. A ponieważ$_
gwarantuje się, że zawiera\n
on, to w rzeczywistości bezpieczne jest nadużywanie globalnego skrótu perla do przechowywania ciągów wyróżniających, więc$$_
zamiast$seen{$_}
Do
expression
używam:Zasadniczo „Dla każdego znaku (z wyjątkiem nowej linii) w łańcuchu wyróżniającym, a także
*
dołącz go do bieżącej globu i wrzuć na tablicę globów kandydujących”. Execpt używam\w*
dla*
uzyskać poprawny regex (można używać''
zamiast""
pozbyć się jednego backslashem ale wtedy nie mogłem uruchomić mój kod z linii poleceń). Zauważ, że to również pobiera;
i dodaje je do globów kandydujących, ale później testuje je na przywrócone,$_
które nie ma,;
że ponownie będzie niemożliwym globem i zostanie przycięte.Zauważ, że
/^;/>/\n;/
ma wartość równoważną pustemu ciągowi w przypadku, gdy rozwiązanie nie zostało jeszcze znalezione, więc będzie to działać jako pusty ciąg zastępczy i$_
zostanie przywróconyźródło
-E
Aktywuje najnowszy poziom języka. Potrzebujesz przynajmniej perla,5.10.0
aby móc korzystaćsay
. Więc umieśćuse 5.10.0;
w sekcji nagłówka i będzie działać. Opcje ustawienia poziomu języka liczą się jako bezpłatne, nawet jeśli nie można tego również zrobić-E
. W rzeczywistości wszystkie opcje są obecnie bezpłatne (więc nie muszę nawet liczyćn0
), ale uważam to za zbyt łagodne dla perla1/
rozwiązanie jest prawidłowe! Też muszę pamiętać ...Java 10,
854824796738728703688655652647624 bajtówCo za bałagan. Z pewnością nie jest to łatwe wyzwanie w Javie.
Zdecydowanie można go pograć w golfa o kilkaset bajtów, ale cieszę się, że w końcu teraz działa.Mówiłem ci. :)-5 bajtów dzięki @ceilingcat .
-23 bajty przełącza się z Java 8 na Java 10
Dane wejściowe jako tablica ciągów ścieżek do plików (z katalogami jako oddzielne elementy i wszystkie elementy zawierające wiodące
/
) oraz ciąg znaków z wejściową ścieżką do pliku do odszukania.Wyjaśnienie:
Wypróbuj online. (Przypadki testowe z
ialsohavealongname
/ihavealongnameaswell
mają nieco krótszą długość is.add(x.replaceAll("~+","\\*"));
zostały zastąpione,{s.remove(x);s.add(x.replaceAll("~+","\\*"));}
aby działały w TIO za 5-10 sekund, zamiast przekroczenia limitu czasu po ponad 60 sekundach.)Dodatkowe ogólne wyjaśnienie:
Przykład: Weźmy
/foo, /foo/bar, /foo/barber, /foo/bar/test, /foo/barber/test, /foo/barber/testing, /foo/barber/coding, /foo/test
jako podane ścieżki do pliku ifoo/bar/test
jako wejściową ścieżkę do pliku.1) Zaczynam od podzielenia danych wejściowych ścieżki
/
pliku i generuję wszystkie fragmenty tych oddzielonych słów:2) Następnie generuję wszystkie permutacje z tymi słowami w tej samej kolejności (stosując ponownie
/
pomiędzy i z przodu):3) Następnie przeglądam elementy z powyższej listy i sprawdzam, czy pasuje ona tylko do pojedynczej ścieżki pliku w tablicy wejściowej ścieżek plików. (Robię to, sprawdzając dwie rzeczy: czy liczba ukośników jest taka sama i czy pasuje do wyrażenia regularnego, w którym każdy
*
jest zamieniany.*
.)Jeśli tak: zachowaj (pierwsze) najkrótsze, które zwracamy na końcu.
źródło
>>>
? Wiem, że>>
to bitowa prawidłowa zmiana.>>>
działa tak samo jak>>
. Ale dla liczb całkowitych ujemnych zmienia bit parzystości na 0 (kilka przykładów można zobaczyć tutaj w sekcji „ >> vs >>> ” ).-1>>>1
jest tylko krótszym wariantemInteger.MAX_VALUE
(i1<<31
byłbyInteger.MIN_VALUE
).