Genera tutte le stringhe di rinforzo di lunghezza n


16

Una stringa di parentesi graffa è definita come una stringa composta dai caratteri *()[]in cui le parentesi graffe corrispondono correttamente:

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

Questa è una stringa di parentesi graffa valida:

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

Ma questi non sono:

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

Il tuo compito è quello di scrivere un programma (o una funzione) che, dato un numero intero positivo n, accetta un numero come input e output (o restituisce) tutte le stringhe di parentesi graffe valide di lunghezza n.

specificazioni

  • È possibile generare le stringhe in qualsiasi ordine.
  • È possibile generare un elenco o una stringa separati da un carattere diverso.
  • Il tuo programma deve gestire 0 correttamente. Esiste 1 possibile stringa di parentesi graffa di lunghezza 0, ovvero la stringa vuota "".
  • Questo è , quindi la risposta valida più breve - misurata in byte - vince.

Casi test

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

3
Il numero di voci nell'output è A025235
Gabriel Benamy,

@GabrielBenamy Ah. Mi chiedevo se fosse già stato visto prima. Interessante.
Esolanging Fruit,

2
Qual è la condizione vincente? Presumo programma più breve (codice golf).
Zgarb,


1
Dato che tutti presumono che si tratti di code golf, taggerò di conseguenza la sfida (poiché altrimenti renderebbe in qualche modo inutili tutte le risposte esistenti). Se intendevi un criterio di vincita diverso, potresti considerare di pubblicare una nuova sfida.
Martin Ender,

Risposte:


3

Gelatina, 29 byte

-3 byte grazie a @JonathanAllan

Per favore , avvisami se ci sono problemi / bug / errori o byte che posso eliminare!

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

Provalo online!

Le precedenti soluzioni che avevo:

“[(*)]”ṗµḟ”*œṣ⁾()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ị

Spiegazione (Il mio miglior tentativo di descrizione):

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

Puoi salvare tre byte usando il filtro ( “[(*)]”ṗµḟ”*œṣ⁾()Fœṣ⁾[]FµÐLÐḟ)
Jonathan Allan,

15

Prolog, 69 byte

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

Una delle proprietà più interessanti di Prolog è che in molti casi è in grado di eseguire un programma all'indietro; ad esempio, invece di provare per vedere se qualcosa è vero, puoi generare tutte le soluzioni per cui è vero, e invece di controllare la lunghezza di una stringa, puoi generare tutte le stringhe con una determinata lunghezza. (Un'altra bella proprietà di Prolog è che richiede spazi bianchi dopo la fine di ogni definizione di predicato, e una nuova riga può essere inserita in modo economico come uno spazio; quindi anche i programmi di golf sono spesso abbastanza leggibili.)

Quanto sopra definisce un predicato (l'equivalente di una funzione) bche verifica se una stringa ha una determinata lunghezza ed è una "stringa di controvento" come definita nella domanda. In particolare, lo fa tramite il supporto grammaticale / regex / pattern-match di Prolog che fornisce un po 'di zucchero breve e piacevole per definire questo tipo di espressione (apparentemente questo è standard / portatile, ma non ero a conoscenza di questo mentre originariamente scrivevo la risposta, e quindi supponendo che la risposta avrebbe funzionato su una sola implementazione Prolog; sembra che funzioni su ogni implementazione conforme agli standard, però). Il programma può essere tradotto in inglese abbastanza direttamente; le prime due righe dicono "an s è una stringa vuota, oppure a e seguita da s ; an eè un asterisco, o una s tra parentesi o una s tra parentesi quadre ". La terza riga può essere interpretata come" La b di N può essere A se A è un elenco con lunghezza N e A è una s seguita da un null corda."

Mi sono preso cura di scrivere s(e quindi b) in modo che corrispondano a ciascuna "stringa di parentesi graffe" esattamente in un modo (che è la ragione per cui entrambi se edevono esistere, piuttosto che raggrupparli in un predicato). Questo li rende entrambi completamente reversibili; pertanto bpuò essere utilizzato per generare tutte le "stringhe di parentesi graffe" di una determinata lunghezza, oltre a verificare se una stringa è una stringa di parentesi di una determinata lunghezza (può essere utilizzata anche una terza via tonda, per capire la lunghezza di una parentesi graffa stringa, ma questa è quasi certamente la sua modalità di funzionamento meno utile). L'implementazione è ricorsiva, ad esempio per generare una s , il codice genererà tutte le possibili e non più lunghe della lunghezza richiesta dell'output e aggiungerà tutte le possibili ss che si adattano allo spazio rimanente a loro; poiché ho specificato in anticipo la lunghezza dell'argomento (all'interno di b ), il motore Prolog sa che non è in grado di generare output più lungo della lunghezza indicata, il che consente di terminare la ricorsione.

Ecco un esempio del programma in funzione:

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

sembra che ci dovrebbe essere qualche costo per la sintassi richiesta per specificare se si desidera eseguire il programma "avanti" o "indietro". perl paga 1 byte per ogni cosa di quel genere di cose
Sparr il

Bene, potresti fare una regola secondo cui gli argomenti alla fine sono sempre il valore di ritorno, quindi invertire l'ordine degli argomenti per specificare da che parte stai eseguendo il programma. È abbastanza comune per le lingue del golf capire cosa dovrebbero fare in parte esaminando se hanno ricevuto input, e questo è un principio comparabile. In generale, tuttavia, è difficile stabilire regole che si applichino a ogni lingua possibile; l'esecuzione di builtin come lengthe in appendentrambi i casi è una parte fondamentale del linguaggio e le funzioni utente spesso fanno lo stesso.

Oh, hmm Ho supposto che ci fosse qualche indicazione nel tuo esempio che ha innescato il comportamento in questione.
Sparr,

No, è interamente dovuto a quali argomenti vengono dati. Nel programma sopra, scrivo length(A,N); se Nviene dato e Anon lo è (cosa che succederà se il predicato viene utilizzato nel modo richiesto nel programma), lengthgenererà un elenco Acomposto da Nelementi sconosciuti. L'uso lengthper misurare la lunghezza di un elenco è probabilmente più comunemente usato (anche se usarlo "all'indietro" è abbastanza comune nella programmazione Prolog). La maggior parte dei predicati finisce per funzionare più o meno allo stesso modo (l'unica ragione per cui non lo fanno è se tentare di invertirli costruisca un ciclo infinito, il che è abbastanza comune).

1
@ ais523 -->e DCG in generale sono ISO Prolog standard .
Fatalizza il

5

Haskell, 101 94 byte

7 byte salvati da 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<-["()","[]"]]

Quasi semplice, seguendo la definizione, ma con il ""caso spostato.

Uso:

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

(Il secondo calcolo richiede meno di un secondo su una macchina lenta.)

Vorrei anche condividere il risultato di un altro approccio che mi è venuto in mente mentre pensavo di generare funzioni. Definisce un elenco b di elenchi di stringhe in modo tale che b!!ncontenga tutte le stringhe di rinforzo di lunghezza n. Allo stesso modo, u!!ncontiene tutti gli atomi di dimensione n-1. Una cosa bella è che il codice non utilizza alcun numero. Non è del tutto giocato a golf: ue ipotrebbe essere inline, e manca di certo poche altre opportunità di golf. Sfortunatamente, non sembra che possa essere ridotto rispetto alla prima versione, ma calcola length $ b !! 10ancora più velocemente.

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)

Salvare due byte con b$n-ke b$n-2. Inoltre, sull'ultima riga puoi fare a:b<-["()","[]"]e tornare a:s++b.
Zgarb,

Oh, volevo usare, ["()","[]"]ma non riuscivo a vedere come migliorare la dimensione del codice con esso. Grazie!
Christian Sievers,

4

Mathematica, 116 byte

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

Spiegazione

Characters@"*([)]"

Trova i caratteri della stringa "*([)]", dando il List {"*", "(", "[", ")", "]"}.

... ~Tuples~#

Trova le tuple dell'elenco sopra con lunghezza n.

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

Funzione booleana senza nome per scoprire se la tupla è bilanciata:

#/."*"->Nothing

Elimina tutto "*"nell'input.

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

Eliminare ripetutamente tutte le occorrenze consecutive di "("e ")"o "["e "]"fino a quando l'input non cambia.

... =={}

Controlla se il risultato è vuoto List.

Select[ ... , ... ]

Trova le tuple che danno Truequando viene applicata la funzione booleana.

#<>""&/@

Converti ciascuno Listdei personaggi in Strings.


2
Un po 'inaspettatamente, {x=a___,"(",")",y=b___}|{x,"[","]",y}sembra funzionare.
Martin Ender,

4

Python 2, 128 byte

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

Avvita le regex ricorsive: stiamo usando il parser di Python! Per verificare che, ad esempio, *(**[])*sia una stringa di parentesi graffa, facciamo quanto segue:

  1. Crea una stringa come "*", (0,"*","*", [0,0] ,0) ,"*", in cui ogni secondo carattere di quattro è un carattere delle parentesi graffe e i restanti caratteri sono incollati per renderlo una potenziale espressione di Python.

  2. eval esso.

  3. Se ciò non genera un errore, stampa s[1::4](i caratteri della stringa di parentesi graffe).

I caratteri della colla vengono scelti in modo tale che la stringa che creo sia un'espressione Python valida se e solo se prendere ogni secondo carattere su quattro produce una stringa di parentesi valida.


2

PHP, 149 byte

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));

Utilizza il buon vecchio genera tutto il possibile e quindi il metodo di filtro. Usa come:

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 byte

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

repl.it

Funzione senza nome che restituisce un elenco di stringhe valide di lunghezza n.
Forma tutte le ntuple dei caratteri *()[], li unisce in stringhe usando map(''.join,...)e filtri per quelli che hanno parentesi bilanciate rimuovendo le "coppie" "*"e "()", "[]"a sua volta n, controllando che il risultato sia una stringa vuota (i ntempi sono eccessivi, specialmente per "*"ma è più golfista).


1

Retina , 78 byte

Il conteggio dei byte presuppone la codifica ISO 8859-1.

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

A`;

Provalo online!

Spiegazione

Sto generando tutte le possibili stringhe di lunghezza 5 e quindi filtrare quelle non valide.

.+
$*

Questo converte l'input in unario, usando 1come cifra.

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

Questo ripetutamente ( +) sostituisce il primo ( 1) in ogni riga ( %) in modo tale da creare cinque copie della riga, una per ogni possibile carattere. Questo viene fatto usando le sostituzioni prefisso e suffisso $`e $'per costruire il resto di ogni riga.

Questo loop si interrompe quando non ci sono più 1 secondi da sostituire. A questo punto abbiamo tutte le possibili stringhe di lunghezza N, una su ogni riga.

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

Queste due fasi vengono eseguite separatamente per ciascuna riga ( %). Il primo stadio duplica semplicemente la linea, con un ;per separare le due copie.

Il secondo stadio è un altro loop ( +), che rimuove ripetutamente [], ()o *dalla prima copia della stringa, o rimuove un punto e virgola all'inizio della riga (che è possibile solo dopo che la stringa è completamente scomparsa).

A`;

Le stringhe valide sono quelle che non hanno più un punto e virgola davanti a loro, quindi scartiamo semplicemente tutte le righe ( A) che contengono un punto e virgola.


Ho provato onliny con input 5: ok. Con l'ingresso 6 ho ricevuto una pagina di errore
edc65,

@ edc65 Funziona per me, ma ovviamente questo approccio non è esattamente efficiente, quindi ci vogliono alcuni secondi. Che tipo di pagina di errore intendi?
Martin Ender,

Ingresso 5: risposta in 3 sec. Input 6: dopo 7 secondi, all'interno della casella Output, ottengo la fonte html di quella che probabilmente è una pagina di errore dal mio proxy. Se è un timeout, allora è un timeout molto breve ... Stavo cercando di ottenere un test case corretto per l'ingresso 6, dato che la mia risposta sembra ok fino all'ingresso 5, ma sbagliata per 6 o più
edc65

@ edc65 Richiede sicuramente più di 7 secondi e il timeout di TIO è di un minuto. Non ho mai visto l'errore che descrivi, potrebbe valere la pena segnalarlo nella chat TIO (o se preferisci su gitter o GitHub ). Per quanto riguarda l'output di riferimento, ecco cosa ottengo per l'input 6: pastebin.com/WmmPPmrc (l'input 7 richiede più di un minuto.)
Martin Ender,

1

Python 3.5, 146 byte

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

Molto lungo rispetto ad altre risposte, ma la più breve che potessi trovare attualmente. È sotto forma di una funzione lambda anonima e quindi deve essere chiamata nel formato

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

Emette un set di Python di stringhe non ordinate che rappresentano tutte le possibili stringhe di parentesi graffe della lunghezza di input.

Ad esempio, supponendo che la funzione precedente sia denominata G, il richiamo G(3)comporterebbe il seguente output:

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

Provalo online! (Ideone)


Tuttavia, se, come me, non sei davvero un fan di semplificare le cose utilizzando built-in, quindi qui è la mia originale risposta non utilizza alcun librerie esterne per trovare permutazioni, e attualmente pari a un enorme 288 237 byte :

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)]

Ancora una volta, come la risposta concorrente, questa ha la forma di una funzione lambda e quindi deve essere chiamata anche nel formato

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

E genera un elenco Python di stringhe non ordinate che rappresentano tutte le stringhe di rinforzo della lunghezza di input. Ad esempio, se la lambda dovesse essere invocata come G(3), questa volta l'output sarebbe il seguente:

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

Inoltre, questo è anche molto più veloce della mia altra risposta, essendo in grado di trovare tutte le stringhe di lunghezza 11in circa 115 secondi , quelle di lunghezza 10in circa 19 secondi , quelle di lunghezza9 in circa 4 secondi e quelle di lunghezza 8in circa 0,73 secondi sulla mia macchina, mentre la mia risposta in competizione richiede molto più di 115 secondi per un input di 6.

Provalo online! (Ideone)


0

05AB1E, 23 byte

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

Alcune di queste funzionalità potrebbero essere state implementate dopo la pubblicazione della domanda. Eventuali suggerimenti sono benvenuti!

Provalo online!

Come?

…[(* - 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

Non conosco 05AB1E, ma non potrebbe *essere anche nell'array di rimozione? E il õQcontrollo potrebbe essere sostituito con qualcosa come NOT?
Esolanging Fruit,

Il primo suggerimento non salverà alcun byte: '*м„()„[]‚õ:vs „()„[]‚'*«õ:(non testato), poiché non esiste alcun comando per concatenare 3 valori AFAIK. Il secondo non funzionerà poiché non esiste un NOT che funzionerebbe così su una stringa, AFAIK. (Dove AFAIK rappresenta "per quanto ne so")
Zacharý,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.