Staffe ad incastro


30

Scrivi un programma o una funzione che accetta una stringa di otto byte contenente uno di ciascuno dei caratteri ()[]{}<>disposti in modo tale che i quattro rispettivi tipi di parentesi corrispondano. Ad esempio, l' ]<([){}>input non è valido perché le parentesi quadre non corrispondono (sebbene tutte le altre lo facciano).

Stampa o restituisce un numero intero da 0a 6che indica quanti dei sei possibili accoppiamenti dei quattro tipi di parentesi sono interbloccati. Le coppie di tipi di parentesi sono considerate interbloccate se si verifica esattamente una parentesi di un tipo tra le parentesi dell'altro tipo. Così([)] e [(])sono bloccati ma ()[], [](), ([]), e [()]non lo sono.

Vince il codice più breve in byte.

Esempi di input / output

()[]{}<> : 0
([{<>}]) : 0
<>{[]}() : 0
{<>([])} : 0
<(>)[{}] : 1
<[({)}]> : 1
[{<}]>() : 2
{<>([}]) : 2
<{(>})[] : 3
[(]<){>} : 3
<([>{)}] : 4
(<{[>})] : 4
(<[{)>}] : 5
<{[(>})] : 5
[{<(]}>) : 6
(<{[)>}] : 6

Risposte:


17

CJam, 18 anni

l7~f&_f{\/~;&}s,2/

Grazie isaacg per alcune idee di golf :)
Provalo online o prova tutti gli esempi

Spiegazione:

l         read a line of input
7~f&      clear the lowest 3 bits of each character
           the goal is to convert brackets of the same type to the same char
_         duplicate the resulting string, let's call it S
f{…}      for each character in S, and S (the char and S are pushed every time)
  \       swap the character with S
  /       split S around that character, resulting in 3 pieces:
           before, between, after
  ~       dump the pieces on the stack
  ;       pop the last piece
  &       intersect the first 2 pieces
          after the loop, we have an array of strings
          containing the chars interlocking to the left with each char of S
s         join all the string into one string
,         get the string length
2/        divide by 2, because S has duplicated characters

1
Oh, quindi sei il ragazzo che ha creato CJam ?? Mi devi delle risposte perse che sono state battute dalle risposte di CJam! ;)
kirbyfan64sos,

6
@Kirbyfan64sos bene, è meglio che inizi a impararlo anche se vuoi vincere :)
aditsu,

9
7~f&? Mi piace già questa risposta e non ho nemmeno letto il resto.
Dennis,

11

Python 2, 163 byte

def f(b,e='([{<)]}>',q=range(4)):
 b=[b[b.index(e[j])+1:b.index(e[j+4])]for j in q]
 print sum(sum(abs(b[k].count(e[j])-b[k].count(e[j+4]))for j in q)for k in q)/2

Questo esamina le cose tra ogni coppia di parentesi corrispondenti e conta il numero di singole parentesi sinistre o destre presenti. La somma di questi divisa per due è l'output.

Sono sicuro che potrebbe essere giocato a golf molto più da golfisti migliori di me.


31
Bene, è successo. Calvin ha pubblicato una risposta. I tempi della fine sono alle porte.
Alex A.

4

GNU sed -r, 147

L'output è unario secondo questa meta-risposta .

y/([{</)]}>/
s/.*/\t& & & & /
:b
y/)]}>/]}>)/
s/\S*>(\S*)>\S* /\1\t/
t
s/\S* //
:
s/(\t\S*)(\S)(\S*)\2(\S*\t)/\1\3\4/
t
s/\S *$/&/
tb
s/\s//g
s/../1/g

Nota: sostituire \tcon effettivotab caratteri per ottenere il punteggio corretto. Tuttavia, il programma funzionerà in entrambi i modi con GNU sed.

Provalo online .


3

Perl, 77 byte

76 codice + 1 interruttore

perl -pe 'y/)]}>/([{</;for$x(/./g){$h{$x="\\$x"}++&&s!$x(.*)$x!$z+=length$1,$1!e}$_=$z'

Riceve input da STDIN e il programma deve essere riavviato per ogni input.

Spiegazione

  1. Sostituire tutte le staffe di chiusura con le loro controparti aperte ( y/.../.../).
  2. Quindi, per ogni carattere nella stringa di input ( for$x...), incrementa un contatore per il carattere ( $h{$x}++).
  3. Se è la seconda volta che vediamo il personaggio, ottieni la distanza tra le due occorrenze ( length $1) e rimuovi entrambe le occorrenze di questo personaggio dalla stringa. Ad esempio, se la stringa fosse ([{([{<<, ci sono due caratteri [e {tra le due (s. Dopo che le (s sono state elaborate, la stringa diventa [{[{<<e noi aggiungiamo 2 al numero totale ($z ) di parentesi graffe.
  4. Il risultato è tratto da $z( $_=$z)

3

Pyth, 20 byte

JmC/CdTzlsm@FPcsJd{J

Suite di test

JmC/CdTz: In primo luogo, questo converte ogni coppia di simboli in un singolo carattere mappando ciascun carattere di input nel suo codice carattere ( Cd) diviso per 10 ( / T), che è lo stesso per ogni coppia ma diverso tra tutte le coppie. Il numero risultante viene riconvertito in un personaggio per essere rivelato in seguito ( C). L'elenco di caratteri risultante viene salvato in J.

lsm@FPcsJd{J: Ora, mappiamo i caratteri univoci in J( {J). Iniziamo tagliando la stringa formata concatenando Jusando il carattere corrente come delimitatore ( csJd). Una coppia di parentesi si sovrappone alla coppia corrente se appare nel secondo gruppo e nel primo o nel terzo gruppo. Per evitare il doppio conteggio, contiamo solo il primo e il secondo caso di gruppo. Quindi, rimuoviamo il terzo gruppo ( P) e prendiamo l'intersezione dei gruppi rimanenti ( @F). Infine, concateniamo i caratteri di sovrapposizione ( s) e stampiamo la lunghezza del resut ( l).


3

Python 3, 107

t=0
s=""
for x in input():s+=chr(ord(x)&~7)
for x in s:a=s.split(x);t+=len(set(a[0])&set(a[1]))
print(t//2)

Liberamente basato sulla mia soluzione CJam.


3

Retina , 128 108 64 62 55 byte

(T`)]>}`([<{
(\D)(.*)\1(.*)
\n$2\n$3
(?=(\D).*\n.*\1)
1
\n
<empty>

Dove <empty>rappresenta una riga finale vuota. Ai fini del conteggio, inserire ogni riga in un file separato e sostituirla \ncon i caratteri di avanzamento riga effettivi. Per comodità, puoi utilizzare questo codice equivalente con il -sflag da un singolo file:

(T`)]>}`([<{
(\D)(.*)\1(.*)
#$2#$3
(?=(\D)[^#]*#[^#]*\1)
1
#
<empty>

L'output è unario .

Spiegazione

Il primo (dice a Retina di eseguire l'intero codice in un ciclo fino a quando un'iterazione smette di cambiare la stringa. In questo caso, ripeterà sempre quattro volte, una volta per ogni tipo di parentesi.

T`)]>}`([<{

Questo trasforma semplicemente ciascuna parentesi di chiusura nella corrispondente parentesi di apertura, in modo che possiamo abbinare le parentesi corrispondenti con un semplice riferimento successivo. (Questa fase diventa no-op dopo la prima iterazione. È inclusa solo nel ciclo, perché il Tgià richiesto un backtick, quindi l'aggiunta (costa solo uno invece di due byte.)

(\D)(.*)\1(.*)
\n$2\n$3

Questo sostituisce la coppia di parentesi più a sinistra con newline. Usiamo \Dper distinguere le parentesi dalle 1s che aggiungiamo più avanti nel ciclo per il conteggio. Alla (.*)fine garantisce che venga sostituita solo una coppia (poiché le partite non possono sovrapporsi).

(?=(\D).*\n.*\1)
1

L'intera regex è in uno sguardo, quindi questo corrisponde a una posizione . Più specificamente corrisponde a una posizione per ciascuna coppia di parentesi che è stata separata dalle altre parentesi che abbiamo appena trasformato in nuove righe. A 1è inserito in ciascuna di queste posizioni. Possiamo semplicemente lasciare 1lì le s, perché non influenzano nessuna delle altre regex (perché le \Ds assicurano che non le abbiniamo accidentalmente).

\n
<empty>

Infine, rimuoviamo le nuove righe (ovvero i segnaposto per l'attuale tipo di parentesi) - questo significa che abbiamo ridotto il problema rimanente a una stringa di lunghezza 6 contenente solo 3 tipi di parentesi, ma per il resto funziona esattamente lo stesso.

Alla fine, 1rimarranno solo le s che abbiamo inserito e il loro importo corrisponde esattamente al numero di parentesi graffe.


2

JavaScript (ES7), 121 117 byte

x=>(a=b=0,[for(c of x)for(d of'1234')(e=c.charCodeAt()/26|0)==d?a^=1<<d:b^=(a>>d&1)<<d*4+e],f=y=>y&&y%2+f(y>>1))(b)/2

Wow. È stato divertente. Ho delineato un'idea di risposta quando è stata lanciata questa sfida, ma era lunga più di 150 byte e non volevo sforzarmi di giocarci a golf. Ieri ho incontrato questa idea sul mio taccuino e ho deciso che non avrei smesso di pensarci fino a quando non avessi completamente giocato a golf. Ho finito per scrivere due algoritmi completamente nuovi, il primo dei quali è risultato più corto di alcuni byte dopo aver golfato di circa 25 byte con tonnellate di bit-hacking.

Come funziona

Innanzitutto impostiamo le variabili ae bto 0. aè un array binario a 4 bit di quali coppie di parentesi ci troviamo attualmente, ed bè un array binario a 16 bit di cui coppie di parentesi sono collegate tra loro.

Successivamente, passiamo in rassegna ciascun personaggio cin x, e ogni carattere din '0123'. Innanzitutto determiniamo con quale tipo di parentesi si ctrova e=c.charCodeAt()/26-1|0. I codici dei caratteri decimali di ciascun tipo di parentesi sono i seguenti:

() => 40,41
<> => 60,62
[] => 91,93
{} => 123,125

Dividendo per 26, sottraendo 1 e pavimentando, li mappiamo su 0, 1, 2 e 3, rispettivamente.

Quindi controlliamo se questo numero è uguale al valore corrente di d. In tal caso, stiamo entrando o uscendo dal dtipo di parentesi th, quindi inseriamo il dbit th acon a^=1<<d. Se non lo è, ma ci sono all'interno del dtipo di staffa °, abbiamo bisogno di capovolgere el'esimo bit nella desimo sezione di 4 bit di b. Questo è fatto così:

b^=(a>>d&1)<<d*4+e

(a>>d&1)Restituisce il dth bit in a. Se siamo all'interno del dtipo di parentesi quinta, questo restituisce 1; in caso contrario, restituisce 0. Successivamente, spostiamo questo a sinistra di d*4+ebit e XOR in bbase al risultato. Se siamo all'interno del dtipo di parentesi th, questo XOR rappresenta il d*4+eth bit di b; altrimenti, non fa nulla.

Alla fine di tutto il loop, bconterrà un numero di 1 bit pari al doppio del valore di ritorno desiderato. Ma dobbiamo ancora capire quanti bit sono. Ecco dove fentra in gioco la sub-funzione :

f=y=>y&&y%2+f(y>>1)

Se yè 0, questo restituisce semplicemente 0. Altrimenti, prende l'ultimo bit di ywith y%2, quindi aggiunge il risultato dell'esecuzione di tutto tranne l'ultimo bit yattraverso la funzione. Per esempio:

f(y)         => y && y%2 + f(y>>1)
f(0b1001101) =>       1  + f(0b100110) = 4
f(0b100110)  =>       0  + f(0b10011)  = 3
f(0b10011)   =>       1  + f(0b1001)   = 3
f(0b1001)    =>       1  + f(0b100)    = 2
f(0b100)     =>       0  + f(0b10)     = 1
f(0b10)      =>       0  + f(0b1)      = 1
f(0b1)       =>       1  + f(0b0)      = 1
f(0b0)       => 0                      = 0

Eseguiamo bquesta funzione e dividiamo il risultato per 2, e c'è la nostra risposta.


1

Oracle SQL 11.2, 206 byte

WITH v AS(SELECT b,MIN(p)i,MAX(p)a FROM(SELECT SUBSTR(TRANSLATE(:1,'])>}','[(<{'),LEVEL,1)b,LEVEL p FROM DUAL CONNECT BY LEVEL<9)GROUP BY b)SELECT COUNT(*)FROM v x,v y WHERE x.i<y.i AND x.a<y.a AND y.i<x.a;

Non golfato:

WITH v AS( -- Compute min and max pos for each bracket type
           SELECT b,MIN(p)i,MAX(p)a 
           FROM   ( -- replace ending brackets by opening brakets and split the string  
                    SELECT SUBSTR(TRANSLATE(:1,'])>}','[(<{'),LEVEL,1)b,LEVEL p 
                    FROM DUAL 
                    CONNECT BY LEVEL<9
                  )
           GROUP BY b
         )
SELECT COUNT(*)
FROM   v x,v y
WHERE  x.i<y.i AND x.a<y.a AND y.i<x.a -- Apply restrictions for interlocking brackets  
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.