Wygeneruj wszystkie nawiasy klamrowe o długości n


16

Ciąg nawiasów klamrowych jest zdefiniowany jako ciąg składający się ze znaków, *()[]w których nawiasy klamrowe pasują poprawnie:

[brace-string] ::= [unit] || [unit] [brace-string]
[unit]         ::= "" || "*" || "(" [brace-string] ")" || "[" [brace-string] "]"

To jest prawidłowy nawias klamrowy:

((())***[]**)****[(())*]*

Ale to nie są:

)(
**(**[*](**)
**([*)]**

Twoim zadaniem jest napisanie programu (lub funkcji), który przy dodatniej liczbie całkowitej nprzyjmuje liczbę jako dane wejściowe i wyjściowe (lub zwraca) wszystkie prawidłowe ciągi nawiasów o długości n.

Dane techniczne

  • Możesz wyprowadzać ciągi w dowolnej kolejności.
  • Możesz generować jako listę lub ciąg znaków oddzielony innym znakiem.
  • Twój program musi poprawnie obsługiwać 0. Istnieje 1 możliwy ciąg nawiasu klamrowego o długości 0, który jest pustym ciągiem "".
  • To jest , więc wygrywa najkrótsza ważna odpowiedź - mierzona w bajtach .

Przypadki testowe

0. 
1. *
2. ** () []
3. *** ()* []* (*) [*] *() *[]
4. **** ()** []** (*)* [*]* (**) **() **[] *(*) *[*] (()) ()() ()[] ([]) [**] [()] [[]] []() [][] *()* *[]*

3
Liczba pozycji na wyjściu to A025235
— Gabriel Benamy,

@GabrielBenamy Ah. Zastanawiałem się, czy wcześniej na to spojrzano. Ciekawy.
— Esolanging Fruit

2
Jaki jest warunek wygranej? Zakładam najkrótszy program (code golf).
— Zgarb


1
Ponieważ wszyscy zakładają, że jest to golf golfowy, odpowiednio oznaczę to wyzwanie (ponieważ w przeciwnym razie wszystkie istniejące odpowiedzi byłyby nieco bezcelowe). Jeśli zamierzałeś zastosować inne kryterium wygranej, możesz rozważyć opublikowanie nowego wyzwania.
— Martin Ender

Odpowiedzi:


3

Galaretka, 29 bajtów

-3 bajty dzięki @JonathanAllan

Proszę powiadom mnie, jeśli są jakieś problemy / bugi / błędy lub bajty mogę strącać!

“[(*)]”ṗµḟ”*œṣ⁾()Fœṣ⁾[]FµÐLÐḟ

Wypróbuj online!

Poprzednie rozwiązania miałem:

“[(*)]”ṗµḟ”*œṣ⁾()Fœṣ⁾[]FµÐL€Ṇ€Tị
“[(*)]”ṗµ¹ḟ”*œṣ⁾()Fœṣ⁾[]FµÐL€Ṇ€Tị
“[(*)]”ṗµ¹ḟ”*œṣ⁾()Fœṣ⁾[]FµÐL€Ṇ€×Jḟ0ị
“[(*)]”x⁸ṗ⁸Qµ¹ḟ”*œṣ⁾()Fœṣ⁾[]FµÐL€Ṇ€×Jḟ0ị
“[(*)]”x⁸ṗ⁸Qµ¹µḟ”*œṣ⁾()Fœṣ⁾[]FµÐL€Ṇ€×Jḟ0ị
“[(*)]”x⁸ṗ⁸Qµ¹µḟ”*œṣ⁾()Fœṣ⁾[]FµÐLµ€Ṇ€×Jḟ0ị

Objaśnienie (Moja najlepsza próba opisu):

Input n
“[(*)]”ṗ-All strings composed of "[(*)]" of length n
µḟ”*    -Filter out all occurences of "*"
œṣ⁾()   -Split at all occurences of "()"
F       -Flatten
œṣ⁾[]   -Split at all occurences of "[]"
F       -Flatten
µÐL     -Repeat that operation until it gives a duplicate result
Ðḟ      -Filter

Możesz zapisać trzy bajty za pomocą filtrowania ( “[(*)]”ṗµḟ”*œṣ⁾()Fœṣ⁾[]FµÐLÐḟ)
— Jonathan Allan,

15

Prolog, 69 bajtów

s-->[];e,s.
e-->"*";"(",s,")";"[",s,"]".
b(N,A):-length(A,N),s(A,[]).

Jedną z najbardziej interesujących właściwości Prologa jest to, że w wielu przypadkach jest on w stanie uruchomić program wstecz; na przykład, zamiast sprawdzać, czy coś jest prawdą, możesz wygenerować wszystkie rozwiązania, dla których jest to prawda, i zamiast sprawdzać długość łańcucha, możesz wygenerować wszystkie łańcuchy o określonej długości. (Inną fajną właściwością Prologa jest to, że wymaga on spacji po zakończeniu każdej definicji predykatu, a nową linię można wstawić tak tanio jak spację; w ten sposób nawet programy w golfa są często dość czytelne).

Powyższe definiuje predykat (odpowiednik funkcji), bktóry sprawdza, czy łańcuch ma określoną długość i jest „łańcuchem nawiasowym”, jak zdefiniowano w pytaniu. Dokładniej, robi to poprzez wsparcie gramatyki Prologa / wyrażenia regularnego / dopasowania wzorca, które daje trochę miłego, krótkiego cukru do zdefiniowania tego rodzaju wyrażeń (najwyraźniej jest to standardowy / przenośny, ale nie wiedziałem o tym podczas pisania odpowiedzi, a zatem założono, że odpowiedź zadziała tylko na jednej implementacji Prolog; wydaje się, że działa na każdej implementacji zgodnej ze standardami). Program można bezpośrednio przetłumaczyć na angielski; pierwsze dwa wiersze mówią: „ s jest pustym ciągiem lub e po którym następuje s ; an ejest gwiazdką lubsw nawiasach lub sw nawiasach kwadratowych. Trzeci wiersz może być interpretowany jako „ b z N może być A, jeśli A jest listą o długości N, a A to s, po którym następuje łańcuch zerowy”.

Wziąłem trochę opieki napisać s(i tym samym b), tak aby dopasować każdy nawias „ciąg” w dokładnie jeden sposób (co jest powodem, że zarówno si emuszą istnieć, zamiast grupując je w jednym orzecznika). To sprawia, że ​​oba są całkowicie odwracalne; dlatego bmożna go wykorzystać do wygenerowania wszystkich „łańcuchów nawiasu klamrowego” o danej długości, oprócz testowania, czy łańcuch jest struną nawiasu klamrowego o danej długości (można go również użyć w drugą stronę, aby obliczyć długość nawiasu string, ale prawie na pewno jest to najmniej przydatny tryb działania). Implementacja jest rekurencyjna, np. Aby wygenerować s , kod wygeneruje wszystkie możliwe e , które nie są dłuższe niż wymagana długość wyjścia, i dołączy wszystkie możliwe ss, które pasują do nich w pozostałej przestrzeni; ponieważ z góry podałem długość argumentu (w ramach b ), silnik Prolog wie, że nie może wygenerować wyniku dłuższego niż podana długość, co pozwala na zakończenie rekursji.

Oto przykład działającego programu:

| ?- b(4,A),format("~s ",[A]),fail.
**** **() **[] *()* *(*) *[]* *[*] ()** ()() ()[] (*)* (**) (()) ([]) []** []() [][] [*]* [**] [()] [[]]

wydaje się, że składnia wymaga pewnego kosztu, aby określić, czy chcesz uruchomić program „do przodu”, czy „do tyłu”. perl płaci 1 bajt za każdą rzecz tego rodzaju
— Sparr

Cóż, możesz wprowadzić regułę, że argumenty na końcu są zawsze wartością zwracaną, a następnie odwrócić kolejność argumentów, aby określić, w którą stronę uruchamiasz program. Języki gry w golfa dość często zastanawiają się, co powinni robić, patrząc na to, czy otrzymali jakieś uwagi, i jest to porównywalna zasada. Zasadniczo jednak trudno jest stworzyć reguły, które będą się odnosić do każdego możliwego języka; uruchamianie wbudowanych jak lengthi appendna odwrót jest podstawową częścią języka, a funkcje użytkownika często robią to samo.

Och, hmm. Zakładam, że w twoim przykładzie było pewne wskazanie, które wywołało dane zachowanie.
— Sparr

Nie, to całkowicie z powodu podanych argumentów. W powyższym programie piszę length(A,N); if Njest podane i Anie jest (co stanie się, jeśli predykat zostanie użyty w sposób wymagany w programie), lengthwygeneruje listę Askładającą się z Nnieznanych elementów. Używanie lengthdo mierzenia długości listy jest prawdopodobnie częściej używane (chociaż używanie „wstecz” jest dość powszechne w programowaniu Prolog). Większość predykatów kończy się w ten sam sposób (jedynym powodem, dla którego nie działają, jest próba ich odwrócenia w celu utworzenia nieskończonej pętli, co jest dość powszechne).

1
@ ais523 -->i ogólnie DCG są standardowym Prologiem ISO .
— Fatalize

5

Haskell, 101 94 bajtów

7 bajtów zapisanych przez Zgarb!

b 0=[""]
b n=[x++y|k<-[1..n],x<-u k,y<-b$n-k]
u 1=["*"]
u n=[a:s++b|s<-b$n-2,a:b<-["()","[]"]]

Prawie proste, zgodne z definicją, ale z ""przeniesioną obudową.

Posługiwać się:

*Main> map b [0..3]
[[""],["*"],["**","()","[]"],["***","*()","*[]","()*","[]*","(*)","[*]"]]
*Main> length $ b 10
21595

(Drugie obliczenie zajmuje mniej niż sekundę na wolnym komputerze).

Chciałbym również podzielić się wynikiem innego podejścia, które wymyśliłem, myśląc o generowaniu funkcji. Definiuje listę b takich łańcuchów, która b!!nzawiera wszystkie łańcuchy nawiasów o długości n. Podobnie u!!nzawiera wszystkie atomy wielkości n-1. Jedną fajną rzeczą jest to, że kod nie używa żadnych cyfr. To nie jest całkowicie golfed: ui imogą być wstawiane, a to z pewnością nie zdobywa kilka innych możliwości gry w golfa. Niestety nie wygląda na to, że można go skrócić do pierwszej wersji, ale oblicza się length $ b !! 10jeszcze szybciej.

b=[""]:b%u
u=["*"]:map i b
i=concatMap(\s->['(':s++")",'[':s++"]"])
(b:c)%f=zipWith(++)[[x++y|x<-b,y<-e]|e<-f]([]:c%f)

Zaoszczędź dwa bajty za pomocą b$n-ki b$n-2. Również w ostatniej linii możesz zrobić a:b<-["()","[]"]i wrócić a:s++b.
— Zgarb

Och, chciałem użyć, ["()","[]"]ale nie mogłem zobaczyć, jak poprawić rozmiar kodu. Dzięki!
— Christian Sievers

4

Mathematica, 116 bajtów

#<>""&/@Select[Characters@"*([)]"~Tuples~#,(#/."*"->Nothing//.{a___,"(",")",b___}|{a___,"[","]",b___}:>{a,b})=={}&]&

Wyjaśnienie

Characters@"*([)]"

Znajdź znaki ciągu "*([)]", podając List {"*", "(", "[", ")", "]"}.

... ~Tuples~#

Znajdź krotki z powyższej listy o długości n.

(#/."*"->Nothing//.{a___,"(",")",b___}|{a___,"[","]",b___}:>{a,b})=={}&

Nienazwana funkcja boolowska, aby sprawdzić, czy krotka jest zrównoważona:

#/."*"->Nothing

Usuń wszystko "*"z wejścia.

... //.{a___,"(",")",b___}|{a___,"[","]",b___}:>{a,b}

Wielokrotnie usuwaj wszystkie kolejne wystąpienia "("i ")"lub "["i "]"dopóki dane wejściowe się nie zmienią.

... =={}

Sprawdź, czy wynik jest pusty List.

Select[ ... , ... ]

Znajdź krotki, które dają Truepo zastosowaniu funkcji boolowskiej.

#<>""&/@

Konwertuj każdy Listze znaków na Strings.


2
Nieoczekiwanie {x=a___,"(",")",y=b___}|{x,"[","]",y}wydaje się działać.
— Martin Ender

4

Python 2, 128 bajtów

n=input()
for i in range(5**n):
 try:s=','.join('  "00([*])00"  '[i/5**j%5::5]for j in range(n));eval(s);print s[1::4]
 except:1

Przykręć rekursywne wyrażenia regularne - używamy parsera Pythona! Aby sprawdzić, na przykład, że *(**[])*jest to nawias klamrowy, wykonujemy następujące czynności:

  1. Utwórz ciąg podobny do tego "*", (0,"*","*", [0,0] ,0) ,"*", w którym co drugi czteroosobowy znak jest znakiem z nawiasów klamrowych, a pozostałe znaki są klejem, aby uczynić z niego potencjalne wyrażenie w języku Python.

  2. eval to.

  3. Jeśli nie spowoduje to błędu, wydrukuj s[1::4](znaki nawiasu klamrowego).

Do kleju znaki są zbierane tak, że ciąg robię jest poprawnym wyrażeniem Pythona tylko wtedy, gdy przy każdym drugi znak z czterech rentowności ważny klamra-strunowych.


2

PHP, 149 bajtów

for(;$argv[1]--;$l=$c,$c=[])foreach($l?:['']as$s)for($n=5;$n--;)$c[]=$s.'*()[]'[$n];echo join(' ',preg_grep('/^((\*|\[(?1)]|\((?1)\))(?1)?|)$/',$l));

Używa starego dobrego generowania wszystkich możliwych, a następnie metody filtrowania. Użyj jak:

php -r "for(;$argv[1]--;$l=$c,$c=[])foreach($l?:['']as$s)for($n=5;$n--;)$c[]=$s.'*()[]'[$n];echo join(' ',preg_grep('/^((\*|\[(?1)]|\((?1)\))(?1)?|)$/',$l));" 4

1

Python, 134 bajty

from itertools import*
lambda n:[x for x in map(''.join,product('*()[]',repeat=n))if''==eval("x"+".replace('%s','')"*3%('*',(),[])*n)]

repl.it

Nienazwana funkcja, która zwraca listę prawidłowych ciągów długości n.
Formy wszystkie długość nkrotki bohaterów *()[], łączy je w ciągi korzystających map(''.join,...)i filtry do tych, które zostały zrównoważone nawiasy usuwając „parę” "*", "()"oraz "[]"z kolei nrazy i upewnieniu się, że wynik jest pustym ciągiem znaków ( nczas jest przesadą, zwłaszcza "*"jednak jest golfistą).


1

Siatkówka , 78 bajtów

Liczba bajtów zakłada kodowanie ISO 8859-1.

.+
$*
+%1`1
*$'¶$`($'¶$`)$'¶$`[$'¶$`]
%(`^
$';
)+`(\[]|\(\)|\*)(?=.*;)|^;

A`;

Wypróbuj online!

Wyjaśnienie

Generuję wszystkie możliwe ciągi o długości 5, a następnie odfiltrowuję niepoprawne.

.+
$*

Konwertuje to wejście na jednoargumentowe, używając 1jako cyfry.

+%1`1
*$'¶$`($'¶$`)$'¶$`[$'¶$`]

To wielokrotnie ( +) zastępuje pierwszy ( 1) jeden w każdej linii ( %) w taki sposób, że tworzy pięć kopii linii, po jednej dla każdego możliwego znaku. Odbywa się to za pomocą podstawień prefiksów i sufiksów $`oraz $'konstruowania reszty każdej linii.

Ta pętla zatrzymuje się, gdy nie ma już 1 do zastąpienia. W tym momencie mamy wszystkie możliwe ciągi długości N, po jednym w każdej linii.

%(`^
$';
)+`(\[]|\(\)|\*)(?=.*;)|^;

Te dwa etapy są wykonywane osobno dla każdej linii ( %). Pierwszy etap po prostu powiela linię za pomocą; oddziela dwie kopie.

Drugi etap jest inny układ ( +), które wielokrotnie usuwa [], ()lub *z pierwszego kopię łańcucha, lub usuwa średnik na początku linii (co jest możliwe dopiero wtedy, gdy łańcuch jest całkowicie zniknął).

A`;

Prawidłowe ciągi to te, które nie mają już średnika przed nimi, więc po prostu odrzucamy wszystkie linie ( A) zawierające średnik.


Próbowałem onliny z wejściem 5: ok. Z wejściem 6 dostałem stronę błędu
— edc65

@ edc65 Działa dla mnie, ale oczywiście to podejście nie jest dokładnie skuteczne, więc zajmuje to kilka sekund. Jaki rodzaj strony błędu masz na myśli?
— Martin Ender

Wejście 5: odpowiedź w ciągu 3 sekund Wejście 6: po 7 sekundach w polu Wyjście otrzymuję źródło html strony, która prawdopodobnie jest stroną błędu, z mojego serwera proxy. Jeśli jest to limit czasu, to jest to bardzo krótki limit czasu ... Próbowałem uzyskać odpowiedni przypadek testowy dla wejścia 6, ponieważ moja odpowiedź wydaje się być
— poprawna

@ edc65 To zdecydowanie trwa dłużej niż 7 sekund, a limit czasu TIO wynosi minutę. Nigdy nie widziałem opisywanego błędu, być może warto go omawiać na czacie TIO (lub jeśli wolisz na Gitter lub GitHub ). Jeśli chodzi o dane wyjściowe, oto, co otrzymuję dla wejścia 6: pastebin.com/WmmPPmrc (Wejście 7 zajmuje więcej niż minutę.)
— Martin Ender

1

Python 3.5, 146 bajtów

import re;from itertools import*;lambda f:{i for i in map(''.join,permutations("[()]*"*f,f))if re.fullmatch("(\**\[\**\]\**|\**\(\**\)\**)*|\**",i)}

Bardzo długi w porównaniu z innymi odpowiedziami, ale najkrótszy, jaki udało mi się obecnie znaleźć. Ma on postać anonimowej funkcji lambda i dlatego musi być wywoływany w formacie

print(<Function Name>(<Integer>))

Wyjścia pytona zestawie z nieuporządkowanych ciągów reprezentujących wszystkie możliwe Brace-ciągi długości wejściowego.

Na przykład przy założeniu, że powyższa funkcja ma nazwę G, wywołanie G(3)spowoduje następujące wyniki:

{'[*]', '*()', '*[]', '(*)', '***', '[]*', '()*'}

Wypróbuj online! (Ideone)


Jeśli jednak, podobnie jak ja, nie jesteś fanem upraszczania rzeczy za pomocą wbudowanych funkcji, oto moja własna oryginalna odpowiedź, która nie korzysta z żadnych zewnętrznych bibliotek w celu znalezienia permutacji, a obecnie stoi na ogromnym poziomie 288 237 bajtów :

import re;D=lambda f:f and"for %s in range(%d)"%(chr(64+f),5)+D(f-1)or'';lambda g:[i for i in eval('["".join(('+''.join('"[()]*"['+chr(o)+'],'for o in range(65,65+g))+'))'+D(g)+']')if re.fullmatch("(\**\[\**\]\**|\**\(\**\)\**)*|\**",i)]

Ponownie, podobnie jak odpowiedź konkurencyjna, ta ma postać funkcji lambda i dlatego należy ją również wywołać w formacie

print(<Function Name>(<Integer>))

Python i wysyła listy z nieposortowane ciągów reprezentujących wszystkie Brace-ciągi długości wejściowego. Na przykład, jeśli lambda G(3)miałaby zostać wywołana jako , tym razem wynik byłby następujący:

['*()', '(*)', '*[]', '[*]', '()*', '[]*', '***']

Również ten jest również o wiele szybszy niż moja inna odpowiedź, będąc w stanie znaleźć wszystkie nawiasy klamrowe o długości 11w około 115 sekund , te o długości 10w około 19 sekund , o długości 9w około 4 sekundy i te o długości 8w około 0,73 sekundy na moim komputerze, podczas gdy moja konkurencyjna odpowiedź trwa znacznie dłużej niż 115 sekund na wprowadzenie 6.

Wypróbuj online! (Ideone)


0

05AB1E, 23 bajty

…[(*.∞sãʒ'*м„()„[]‚õ:õQ

Niektóre z tych funkcji mogły zostać zaimplementowane po opublikowaniu pytania. Wszelkie sugestie są mile widziane!

Wypróbuj online!

W jaki sposób?

…[(* - the string '[(*'
.∞ - intersected mirror, '[(*'=>'[(*)]'
s - swap the top two items, which moves the input to the top
ã - cartesian power
ʒ ...  - filter by this code:
  '*м      - remove all occurrences of '*'
  „()„[]‚  - the array ["()","[]"]
  õ        - the empty string ""
  :        - infinite replacement (this repeatedly removes "()", "[]", and "*" from the string
  õQ       - test equality with the empty string

Nie znam 05AB1E, ale czy nie może *być również w tablicy usuwania? I czy õQczek można zastąpić czymś takim, jak NIE?
— Esolanging Fruit

Pierwsza sugestia nie zapisuje żadnych bajtów: '*м„()„[]‚õ:vs „()„[]‚'*«õ:(nie testowane), ponieważ nie ma polecenia konkatenacji 3 wartości AFAIK. Drugi nie zadziała, ponieważ nie ma takiego, który działałby tak na łańcuchu, AFAIK. (Gdzie AFAIK reprezentuje „o ile mi wiadomo”)
— Zacharý
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.