Trova la prima partita di parentesi


22

Questa è stata una delle sfide che hanno portato al compleanno di Brain-Flak. Scopri di più qui .

Sfida

Per questa sfida il tuo obiettivo sarà trovare la prima coppia di parentesi corrispondenti in una stringa di ()[]{}<>parentesi completamente abbinata . Per prendere in prestito la definizione di DJMcMayhem di una stringa completamente abbinata:

  • Ai fini di questa sfida, una "staffa" è uno di questi personaggi: ()[]{}<>.

  • Una coppia di parentesi è considerata "abbinata" se le parentesi aperta e chiusa sono nell'ordine giusto e non hanno caratteri al loro interno, come

    ()
    []{}
    

    O se anche ogni sottoelemento al suo interno è abbinato.

    [()()()()]
    {<[]>}
    (()())
    

    I sottoelementi possono anche essere nidificati a più livelli di profondità.

    [(){<><>[()]}<>()]
    <[{((()))}]>
    
  • Una stringa è considerata "Completamente abbinata" se e solo se ogni coppia di parentesi ha la parentesi aperta e chiusa corretta nell'ordine giusto.

Ingresso

L'input consisterà in una singola stringa non vuota o array di caratteri contenente solo i caratteri ()[]{}<>ed è garantito che corrisponda completamente. Si può prendere in ingresso in modo ragionevole che corrisponde con i nostri di I / O di default .

Produzione

L'output del tuo programma o funzione sarà l'indice della parentesi che chiude il primo. L'output deve essere 0o 1indicizzato. Ancora una volta, l'uscita può essere in qualsiasi maniera ragionevole che corrisponde con le I / O predefiniti .

Casi test

Input       0-indexed   1-indexed
()          1           2
(<>)        3           4
<[]{<>}>    7           8
{}{}{}{}    1           2
[[]<>[]]    7           8

Questo è , vince meno byte!


3
Punti bonus se rispondi in Brain-Flak ofc :)
Erik the Outgolfer

1
@EriktheOutgolfer Done
DJMcMayhem

1
Questa tecnica è molto utile per scrivere implementazioni inefficienti di BF.
Esolanging Fruit,

Risposte:


2

V , 4 byte

%Dø.

Provalo online!

Questo, a differenza della maggior parte delle risposte V, utilizza l'indicizzazione 0. Sono estremamente orgoglioso di questa risposta e di quanto sia arrivata la mia lingua. Spiegazione:

%       " Jump to the first bracket match
 D      " Delete everything under and after the cursor
  ø     " Count the number of times the following regex is matched:
   .    "   Any character

Non è necessario il boilerplate necessario per abbinare <>?
Pavel,

@Pavel In vim, sì. Ma non in V.
DJMcMayhem

27

Brain-Flak , 685, 155, 151 , 137 byte

(())({<{}({}()<(()()()())>)({}(<>))<>{(({})){({}[()])<>}{}}{}<>
([{}()]{})(({})){{}({}[()])(<()>)}{}(<>)<>{{}<>{}({}<>)}{}(<>[]<>)>()}<>)

Provalo online!

136 byte di codice, più un byte per -a. Uno indicizzato.

530 byte sballati! Questo è probabilmente il più grande golf che abbia mai fatto.

14 byte salvati grazie a Riley!

Questo abusa di una formula della parentesi di apertura / chiusura: se prendi i valori ASCII, aumentali di uno e prendi il modulo di 4, gli opener ( ({[<) otterranno sempre 0o 1, mentre i closers ( )}]>) otterranno sempre 2 o 3.

Spiegazione:

#Push 1
(())

#While true
({<

    #Pop stack height
    {}

    #Compute (TOS + 1) % 4
    ({}()<(()()()())>)({}(<>))<>{(({})){({}[()])<>}{}}{}<>([{}()]{})

    #Decrement if positive
    (({})){{}({}[()])(<()>)}{}

    #Push 0 onto alternate
    (<>)

    #Toggle back
    <>

    #Pop two zeros from alternate if closer
    {{}<>{}({}<>)}{}

    #Push height of alternate stack
    (<>[]<>)

#Make each time through evaluate to 1
>()

#Endwhile
}

#Push the number of loops onto the offstack
<>)

8
Per amore di Dio, che diavolo è questo.
Leaky Nun,

Praticamente tutti ora stanno usando n-1&2/ n+1&2/ -n&2o n%7&2per distinguere le parentesi di apertura e chiusura ...
ETHproductions

@ETHproductions Non sono sicuro che il brain-flak sia in grado di calcolare in modo efficiente &2, ma lo esaminerò.
DJMcMayhem

Oh, pensavo che lo fossi. Devi fare qualcosa di simile per distinguere tra 0/ 1e 2/ 3... anche se ora che lo guardo, stai solo diminuendo se positivo. Anche un bel trucco :-)
ETHproductions

1
La (TOS+1)%4può essere più breve: Provalo on-line!
MegaTom,

11

05AB1E , 17 16 10 byte

-1 grazie al carusocomputing

-6 grazie ad Adnan per la sua incredibile intuizione che "dopo l'incremento, il secondo ultimo bit è 0 per una parentesi quadra aperta e 1 per una parentesi quadra chiusa"

Ç>2&<.pO0k

Provalo online!

Ç          # Get input as ASCII values
 >         # Increment
  2&       # And with 2 (0 for open and 2 for close brackets)
    <      # decrement 
     .p    # prefixes
       O   # Sum
        0k # Print the index of the first 0

žusembra utilizzabile qui.
Magic Octopus Urn,

žu8ÝÈÏquindi no, non proprio lol. Nella migliore delle ipotesi saranno ancora 5 byte. Stavo pensando di dividere le coppie di parentesi graffe e rimuovere le parentesi graffe fino a quando rimane solo una coppia, incrementare il contatore di 2 per ogni coppia rimossa. Non ho idea se sia meno però. Provandolo atm.
Magic Octopus Urn,

Per 10 byte: Ç>2&<.pO0k.
Adnan,

1
Sto solo scherzando con i valori ASCII. Si noti che dopo l'incremento, il secondo ultimo bit è 0per una parentesi quadra aperta e 1per una parentesi quadra chiusa.
Adnan,

11

Vim, 23 byte

:se mps+=<:>
%DVr<C-a>C1<esc>@"

Provalo online!

Sono davvero triste per questa risposta. Questa soluzione è meravigliosamente elegante e breve, ma, per impostazione predefinita, vim non considera <e >deve essere abbinata, quindi ho bisogno di 13 byte di codice boilerplate. Altrimenti, questo sarebbe solo 10 byte.

Avrei pubblicato una risposta V, ma sarebbe solo un byte più breve, vale Vra dire passare a Ò, dal momento che Vrè un linguaggio comune di Vim.

Questo è 1-indicizzato ma potrebbe essere banalmente modificato per essere 0-indicizzato cambiando 1in a 0.

:se mps+=<:>        " Stupid boilerplate that tells vim to consider `<` and `>` matched
%                   " Jump to the bracket that matches the bracket under the cursor
 D                  " Delete everything from here to the end of the line
  V                 " Visually select this whole line
   r<C-a>           " Replace each character in this selection with `<C-a>`
                    " This conveniently places the cursor on the first char also
         C          " Delete this whole line into register '"', and enter insert mode
          1<esc>    " Enter a '1' and escape to normal mode
                @"  " Run the text in register '"' as if typed. Since the `<C-a>` command
                    " Will increment the number currently under the cursor

1
Pubblica una risposta V quindi :)
Erik the Outgolfer,

10

Gelatina , 11 10 9 byte

O’&2’+\i0

Provalo online!

Spiegazione

L'idea qui era quella di trovare una "formula magica" in grado di distinguere l'apertura tra parentesi quadre. Inizialmente O%7&2usavo (cioè "prendi il codice ASCII, modulo 7, bitwise-e 2"), ma suggeriva @ETHproductions O’&2(che sostituisce il modulo 7 con un decremento); entrambi restituiscono 0 per un tipo di parentesi e 2 per l'altro. Sottraendo 1 ( ) si trasformeranno questi risultati in -1 e 1.

Il resto del codice è +\. +\produce una somma cumulativa. Se una serie di parentesi è correttamente abbinata, conterrà lo stesso numero di -1 e 1, ovvero la sua somma cumulativa sarà 0. Quindi dobbiamo solo restituire l'indice del primo 0 nell'elenco risultante; possiamo farlo con i0.


Affascinante il modo in cui abbiamo adottato un approccio simile per rilevare parentesi di chiusura. Purtroppo ho trovato solo una versione inferiore:b*2%7>3
2501

Approccio interessante! Ho sviluppato una risposta più lunga (per esercitarmi) che alla fine ho appreso praticamente a questo, tranne che abbastanza interessante, invece del primo decremento nel tuo post, ho avuto invece un incremento. :)
HyperNeutrino,

9

Retina , 26 24 byte

M!`^.(?<-1>([[({<])*.)*

Provalo online!

Il risultato è basato su 1.

Spiegazione

Una soluzione Retina molto diversa che si basa essenzialmente su una regex singola (e molto leggibile ...). Questo utilizza una nuova tecnica che ho scoperto ieri per abbinare le stringhe bilanciate usando i gruppi di bilanciamento .

M!`^.(?<-1>([[({<])*.)*

Trova ( M) e restituisce ( !) tutte le corrispondenze della regex ^.(?<-1>([[({<])*.)*. Quella regex salta il primo carattere della stringa e quindi usa i gruppi di bilanciamento per tenere traccia della profondità di annidamento. Qualsiasi [({<aumento della profondità (tenuto traccia di per gruppo 1) e qualsiasi altro carattere diminuisce la profondità (in linea di principio, .consente di ridurre la profondità anche aprendo le parentesi, ma poiché il regex è abbinato avidamente, il backtracker non tenterà mai che ). Il trucco strano è che il (?<-1>...)gruppo racchiude 1che funziona perché lo scoppio da un gruppo di bilanciamento avviene alla fine del gruppo. Ciò consente di risparmiare due byte rispetto all'approccio standard nel modulo((open)|(?<-2>close))*. La corrispondenza si interrompe necessariamente nella parentesi che chiude la prima, perché l'abbiamo saltata, quindi non viene considerata nella profondità della pila (e la profondità della pila non può andare in negativo).

La lunghezza di questa corrispondenza è l'indice a 0 della parentesi che stiamo cercando.


Basta contare il numero di corrispondenze vuote in questa stringa. Il regex vuoto corrisponde sempre una volta in più rispetto ai caratteri nella stringa, quindi questo ci dà l'indice a 1 sulla parentesi che stiamo cercando.


È geniale!
Pavel,

Approccio più breve : elimina la seconda parte della stringa anziché abbinare la prima parte. Mi piace come hai misurato la lunghezza della corda, a proposito!
Leo,

@Leo È davvero pulito! Puoi pubblicarlo come risposta separata :)
Martin Ender,

Ok, questo nuovo trucco per archi bilanciati è meraviglioso: D
Leo

6

Retina , 24 byte

.(([[({<])|(?<-2>.))*$


Provalo online!

Questo si ispira alla soluzione di Martin Ender .

Spiegazione

La prima riga è una regex che corrisponde a un carattere seguito da una stringa bilanciata che arriva fino alla fine della stringa principale (per una spiegazione dettagliata di come vengono utilizzati i gruppi di bilanciamento in questa regex, vedere la risposta di Martin). Poiché le regex cercano corrispondenze da sinistra a destra, questo troverà il subfisso corretto bilanciato più lungo, ovvero tutto dopo la parentesi che chiude la prima, più la parentesi stessa.

La riga seguente è vuota, quindi sostituiamo la corrispondenza con una stringa vuota, il che significa che ora dobbiamo solo contare i caratteri rimanenti per ottenere il risultato desiderato (indicizzato 0).

L'ultima riga vuota conta il numero di corrispondenze della stringa vuota nella stringa, che è uno in più rispetto al numero di caratteri nella stringa, equivalente al risultato con 1 indice.


Ieri ho trovato una nuova tecnica per abbinare stringhe bilanciate che salva due byte su entrambe le nostre risposte: tio.run/##K0otycxL/K@q4Z7wX0/D3kbX0E4jOlqj2iZWU0tPU0uFi@v/… (e probabilmente una dozzina di altre che ho scritto nel passato ...)
Martin Ender il

5

Perl 5 , 28 byte

Hai salvato 6 byte usando semplicemente .invece di [>})\]], dalla risposta Retina di Martin Ender .

27 byte di codice + -pflag.

/([<{([](?0)*.)+?/;$_=$+[0]

Provalo online!

Regex ricorsivo, che bella invenzione.
L'aspetto regex per una parentesi di apertura ( [<{([]), seguita da chiamata reccursive ( ?0), seguita da una staffa di chiusura ( .). Tutto ciò non avidamente ( +?) in modo che corrisponda il più breve possibile dall'inizio. L'indice della fine della partita è la risposta e, come accade, può essere trovato in $+[0].


4

JavaScript (ES6), 55 53 52 byte

Salvato 1 byte grazie a @Adnan

f=([c,...s],i=1)=>(i-=-c.charCodeAt()&2)&&1+f(s,++i)

Per ogni parentesi aperta, prendendo il suo codice char mod 4 ci dà 0 o 3; per le parentesi di chiusura, ci dà 1 o 2. Pertanto, possiamo distinguere tra parentesi di apertura e chiusura negando il codice char della parentesi (che lancia i bit e sottrae 1) e prendendo il secondo bit meno significativo; cioè n&2.


Penso che invece di n-1&2, -n&2funziona anche?
Adnan,

@Adnan Hmm, penso che tu abbia ragione. Grazie!
ETHproductions

4

C, 75 72 56 55 54 45 byte

a;f(char*s){return(a-=(-*s++&2)-1)?1+f(s):0;}

Guardalo funzionare online .

Se si desidera che l'output sia 1 indicizzato anziché 0 indicizzato, sostituire l'ultimo 0con 1.


4

Python 2.7 + Numpy, 85 79 byte

Il mio primo tentativo di code golf:

from numpy import*
lambda s:list(cumsum([(ord(x)+1&2)-1for x in s])).index(0)

1
Benvenuti nel sito!
DJMcMayhem

1
Non devi nominare lambdas, puoi rimuovere g =
Pavel

4

Brain-Flak , 97 byte (96 per codice, 1 per bandiera)

{}<>(())({<(<()>)<>({<({}[()])><>([{}]())<>}{})<>(<{}>())<>{({}[()])<>([{}])<>}{}<>({}{})>()}{})

Corri con la -abandiera.

Provalo online!

Spiegazione:

#Skip the first open bracket 
{}

#Place a 1 on stack B, representing the nesting depth
<>(())

#Start a loop, until the depth is 0
({<

 #Divide the ASCII code by 2, rounding up
 (<()>)<>({<({}[()])><>([{}]())<>}{})<>

 #Replace TOS B with a 1
 (<{}>())

 #Swap back to stack A
 <>

 #Negate the 1 on stack B n times (n = ASCII value+1/2)
 {({}[()])<>([{}])<>}{}

 #Swap back to stack B
 <>

 #Add the 1/-1 (depending on Open/close bracket) to the nesting depth accumulator
 ({}{})

 #Count loop cycles
 >()

#end loop, print result implicitly by pushing to the stack 
}{}) 

Funziona e basta.


3

Retina , 34 byte

^.
!
T`([{}])`<<<>
+T`p`!`<!*>
\G!

Provalo online!

Il risultato è basato su 0.

Spiegazione

^.
!

Sostituisci il primo carattere con a !. Questo fa sì che la parentesi che stiamo cercando non abbia eguali.

T`([{}])`<<<>

Converti parentesi, parentesi quadre e parentesi graffe in parentesi angolari. Poiché la stringa è garantita per la corrispondenza completa, non ci importa affatto dei tipi effettivi e questo consente di risparmiare alcuni byte nel passaggio successivo.

+T`p`!`<!*>

Ripetutamente ( +) sostituisci ogni personaggio in tutte le partite di <!*>con !s. Cioè, abbiniamo coppie di parentesi che non contengono ulteriori parentesi non trasformate e le trasformiamo in ulteriori punti esclamativi. Ciò trasformerà l'intera stringa tranne la parentesi di chiusura ineguagliata in punti esclamativi.

\G!

Contare il numero di punti esclamativi iniziali, che è uguale alla posizione in base 0 del primo punto esclamativo (ovvero la parentesi senza pari). Le \Gancore corrispondono ciascuna alla precedente, motivo per cui questo non conta le !s dopo detta parentesi.


Ho visto che avevi risposto nella home page e sapevo che avrebbe usato una sorta di regex
Christopher,

@Christopher Eh, questo usa a malapena qualsiasi regex (al contrario dell'altra risposta Retina che ho appena pubblicato ...).
Martin Ender,

Sheesh. Regex molto?
Christopher,

Perché non è questo funziona?
Leaky Nun,

@LeakyNun Perché (?!(2))è giusto (?!2). Probabilmente intendevi (?(2)(?!))o (?2)!). Hai anche dimenticato di sfuggire a ]e il finale +deve essere *.
Martin Ender,

2

PHP, 116 byte

for($l=["("=>")","["=>"]","{"=>"}","<"=>">"][$f=$argn[0]];;$d>0?$i++:die("$i"))$d+=$f!=($n=$argn[$i])?$n==$l?-1:0:1;

Versione online


PHP non deve iniziare con <?php?
Pavel,

@Phoenix: esiste un interprete PHP autonomo che non richiede il tag iniziale. Questo è ciò che viene normalmente utilizzato per il golf.

@ ais523 In questo caso PHP viene eseguito dalla riga di comando con l'opzione -R
Jörg Hülsermann

2

Python , 76 byte

f=lambda s,r=[],i=0:(i<1or sum(r))and f(s[1:],r+[(ord(s[0])+1&2)-1],i+1)or i

Funzione ricorsiva che utilizza il 2 ° LSB ordinale come flag per il trucco aperto vs stretto usato da molti trovati da Adnan (e probabilmente da altri). La coda colpisce quando la somma cumulativa di -1per aprire e 1per chiudere raggiunge lo zero. L'indice viene mantenuto in una variabile poiché è più economico di byte rispetto all'utilizzolen(r) , l'indicizzazione è basata su 1.

Provalo online!


2

Rubino, 35 34 byte

p$_[/[<{(\[](\g<0>)*[>})\]]/].size

Basato sulla risposta di Perl5 di Dada . L'output è 1 indicizzato. Richiede che l'interprete Ruby sia invocato con l' -nopzione (implicitawhile gets ciclo ).

Modifica: anche 35 34 byte, ma è un altro possibile punto di partenza per ridurre ulteriormente questa risposta.

p$_[/[<{(\[](\g<0>)*[>})\]]/]=~/$/

Edit2: rimossi gli spazi non necessari dopo p.

Edit3: un altro paio di risposte a 34 byte.

~/[<{(\[](\g<0>)*[>})\]]/;p$&.size
p~/[<{(\[](\g<0>)*[>})\]]/+$&.size

2
Benvenuti in PPCG!
Pavel

1
Molto apprezzato! :)
Ray Hamel,

2

Python 3 , 59 55 50 49 byte

f=lambda s,n=1:n and-~f(s[1:],n+1-(-ord(s[1])&2))

L'output è indicizzato 0. La formula per determinare la direzione della parentesi è stata scoperta per la prima volta da @ETHProductions e migliorata da @Adnan.

Provalo online!


1

Lotto, 172 byte

@set/ps=
@set/ai=d=0
:l
@set/ai+=1,d-=1
@set c="%s:~,1%"
@set "s=%s:~1%
@for %%a in ("<" "(" "[" "{")do @if %%a==%c% set/ad+=2&goto l
@if %d% gtr 0 goto l
@echo %i%

1-indicizzati. <>ovviamente sono personaggi speciali in Batch, quindi non solo devo citare dappertutto, ma non posso nemmeno fare trucchi come renderli gotoetichette.


1

R, 126 byte

s=readline();i=0;r=0;for(c in strsplit(s,"")[[1]]){if(grepl("[\\[\\(\\{<]",c))i=i+1 else i=i-1;if(i==0){print(r);break};r=r+1}

0

C, 127 byte

Prova online

c(x){x-40&x-60&x-91&x-123?-1:1;}
f(i,t)char*t;{return i?f(i+c(*t),t+1):t;}
s(char*t){return f(c(*t),t+1)-t;}

Produzione

2   ()
4   (<>)
8   <[]{<>}>
2   {}{}{}{}
8   [[]<>[]]

Qualsiasi commento, downvoter.
Khaled.K,

Non ero il downvoter, ma non credo che sia stato d'aiuto che ci fosse già una presentazione C molto più breve.
Ørjan Johansen,
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.