Rovescia una stringa


21

Una stringa bilanciata è una stringa di parentesi in ()modo che ogni parentesi sia abbinata a un'altra. Più rigorosamente sono le stringhe attraversate da questa grammatica:

S → (S)S | ε

Possiamo trasformare una stringa "dentro e fuori" da:

  • Commutazione di tutte le occorrenze reciproche (e )reciproche

  • Spostare i caratteri dalla parte anteriore della stringa verso la parte posteriore fino a quando la stringa non viene nuovamente bilanciata.


Facciamo un esempio.

Iniziamo con la stringa bilanciata:

(()(())())

Quindi cambiamo le parentesi da fare

))())(()((

Quindi sposta i caratteri dalla parte anteriore della stringa alla parte posteriore della stringa fino a quando la stringa non viene bilanciata.

))())(()((
)())(()(()
())(()(())
))(()(())(
)(()(())()
(()(())())

Questo è il nostro risultato!


Si noti che alcune stringhe possono essere capovolte in più modi, ad esempio la stringa

(()())

Se capovolto, può essere:

()(())

o

(())()

Tuttavia, ogni stringa ha almeno una soluzione .

Compito

Scrivi un programma per prendere una stringa bilanciata come input e output quella stringa capovolta. Nei casi in cui potrebbero esserci più output validi, è necessario solo output di uno di essi. È possibile utilizzare un diverso tipo di tutore ( <>, []o {}), se lo si desidera.

Questa è una competizione di , quindi dovresti mirare a ridurre al minimo le dimensioni del tuo codice sorgente, misurato in byte.

Casi test

(()())     -> ()(()), (())()
(()(())()) -> (()(())())
((())())() -> (()(()()))

È garantito che ci sia sempre una soluzione?
Luis Mendo,

@LuisMendo Sì, l'ho dimostrato. Se desideri vedere la prova, sentiti libero di chiamarmi in chat.
Wheat Wizard

Grazie. È sufficiente per me saperlo. Forse dovresti scriverlo nella sfida, altrimenti dovresti definire cosa produrre se nessuna soluzione
Luis Mendo

Risposte:


9

Haskell , 124 120 119 117 113 110 109 106 105 104 101 98 byte

4 byte salvati grazie a bartavelle!

3 byte salvati grazie a Zgarb

1 byte salvato grazie a Peter Taylor

Ecco una soluzione che ho elaborato in Haskell. Il suo ok adesso piuttosto bene grazie a qualche aiuto che ho ricevuto, ma sto cercando di fare questo più breve, in modo da feedback / suggerimenti sono apprezzati.

until(!0)g.map d
_!1=1<0
('(':a)!x=a!(x-1)
(_:a)!x=a!(x+1)
_!_=1>0
g(a:b)=b++[a]
d '('=')'
d _='('

Provalo online!

Spiegazione

Questo programma definisce 4 funzioni, la prima (!)determina se una stringa è bilanciata. È definito come segue:

_!1=1<0
('(':a)!x=a!(x-1)
(_:a)!x=a!(x+1)
_!_=1>0

Questo controllo presuppone che l'ingresso abbia un numero uguale di parentesi aperte e chiuse grazie a un suggerimento di Peter Taylor.

Il prossimo gruoterà la stringa una volta.

g(a:b)=b++[a]

Quindi abbiamo dche prende semplicemente un paren e lo rispecchia

d '('=')'
d _='('

Finalmente abbiamo la funzione di cui ci occupiamo. Qui usiamo una rappresentazione senza punti di until(!0)gcomposta con map d, che si associa dall'input e si applica gfino a quando il risultato è bilanciato. Questo è il processo esatto descritto nella domanda.

until(!0)g.map d

1
È possibile eliminare alcuni byte con g x@(a:b)|x!0=x|1>0=g$b++[a]e rimuovere le parentesi per d '('=')'.
bartavelle,

@bartavelle Rimuovere le parentesi per dcausa un errore del compilatore, credimi, ho provato. Ma il primo suggerimento è il benvenuto. Grazie!
Wheat Wizard

1
È possibile salvare un altro byte !perché non è necessario gestire i casi in cui la stringa ha un numero ineguale di parentesi aperte e chiuse, quindi è possibile scambiare i primi due casi e avere_!1=1<0 []!_=0<1
Peter Taylor

1
Utilizzare untilper abbreviare g: TIO
Zgarb

2
Penso che ci dovrebbe essere un risparmio decente facendo dmappa '('per (-1)e quant'altro per 1, e poi i due casi più lunghe !possono essere combinati per (i:a)!x=a!(x+i). La struttura di livello superiore deve quindi essere rielaborata per map dentrare nella untilcondizione, e devo correre, quindi non ho tempo per capire quali combinatori sono necessari per incollare tutto insieme.
Peter Taylor,

7

SOGL V0.12 , 12 11 byte

↔]»:l{Ƨ()øŗ

Provalo qui!

Spiegazione:

↔            mirror characters
 ]           do ... while the top of stack is truthy
  »            put the last letter at the start
   :           duplicate it
    l{         length times do
      Ƨ()        push "()"
         ø       push ""
          ŗ      replace ["()" with ""]
             if the string left on stack is empty (aka all matched parentheses could be removed), then stop the while loop

Nota: l{potrebbe essere sostituito con ( per 10 byte, ma, purtroppo, non è implementato.


Sei sicuro che il mirroring dei personaggi funzioni? Non so esattamente cosa significhi, ma la mia intuizione mi dice che inverte anche l'ordine dei personaggi che, penso, non funzionerebbe.
Wheat Wizard

1
@Olmman E ' stato destinato per invertire i caratteri, ma non lo fa (che consente di risparmiare un byte qui!). È sulla line-up V0.13s per cambiare trogolo. Esempio
dzaima,

5

CJam (20 caratteri)

q1f^0X${~_}%_:e>#)m<

Demo online

o per lo stesso numero di caratteri

q1f^_,,{0W$@<~}$W=m<

Demo online

Dissezione

Le due versioni hanno un'intestazione e un piè di pagina comuni

q1f^    e# Read input and toggle least significant bit of each character
        e# This effectively swaps ( and )

m<      e# Stack: swapped_string index
        e# Rotates the string to the left index characters

Quindi il bit nel mezzo ovviamente calcola fino a che punto è necessario ruotare. Entrambi utilizzano la valutazione e si affidano (all'operatore di decremento CJam e )all'operatore di incremento.

0X$     e# Push 0 and a copy of the swapped string
{~_}%   e# Map: evaluate one character and duplicate top of stack
        e# The result is an array of the negated nesting depth after each character
_:e>    e# Copy that array and find its maximum value
#       e# Find the first index at which that value occurs
)       e# Increment

vs

_,,     e# Create array [0 1 ... len(swapped_string)-1]
{       e# Sort with mapping function:
  0W$@  e#   Rearrange stack to 0 swapped_string index
  <~    e#   Take first index chars of swapped_string and evaluate
}$      e# The result is an array of indices sorted by the negated nesting depth
W=      e# Take the last one

3

JavaScript (ES6), 111 105 byte

(Salvato 2 byte grazie a @CraigAyre, 2 byte grazie a @PeterTaylor, 2 byte grazie a @Shaggy.)

s=>(r=[...s].map(c=>'()'[c<')'|0])).some(_=>r.push(r.shift(i=0))&&!r.some(c=>(i+=c<')'||-1)<0))&&r.join``

Ungolfed:

s=>(
  r=[...s].map(c=>'()'[c<')'|0]),  //switch "(" and ")"
  r.some(_=>(
    r.push(r.shift(i=0)),          //move last element to beginning of array, initialize i
    !r.some(c=>(i+=c<')'||-1)<0)   //check if balanced (i should never be less than 0)
  )),
  r.join``
)

Casi test:


3

Retina , 46 38 byte

T`()`)(
(.*?)(((\()|(?<-4>\)))+)$
$2$1

Provalo online! Il link include casi di test. Modifica: salvato 8 byte con l'aiuto di @MartinEnder. Il primo stadio traspone semplicemente le parentesi, mentre il secondo stadio cerca il suffisso più lungo che è un prefisso bilanciato valido, che apparentemente è una condizione sufficiente affinché la rotazione sia completamente bilanciata. Il bilanciamento viene rilevato utilizzando i gruppi di bilanciamento. Il costrutto ((\()|(?<-4>\)))+corrisponde a qualsiasi numero di (s più un numero qualsiasi di )s purché abbiamo già ( <-4>) visto altrettanti (s. Dato che stiamo cercando solo un prefisso valido, non dobbiamo abbinare i rimanenti )s.


Normalmente, invece di ripetere entrambe le parentesi, le metti semplicemente in una alternanza, che salva un byte ((\()|(?<-2>\))). Ma il tuo tentativo appena mi ha spinto a trovare un approccio completamente nuovo che consente di risparmiare altri due: (?<-1>(\()*\))+. Questo sarà sicuramente utile in futuro, quindi grazie. :)
Martin Ender,

È ancora più breve determinare la rotazione abbinando il primo suffisso attraverso il quale è possibile raggiungere la fine della stringa senza ottenere una profondità di pila negativa: tio.run/…
Martin Ender,

@MartinEnder Inizialmente avevo provato un'alternativa ma non riuscivo a farlo funzionare in quel momento, ma non riesco a vedere come (?<-1>(\()*\))+funziona, dal momento che sembra voler uscire dallo 1stack prima di aver effettivamente abbinato qualsiasi cosa ...
Neil

@MartinEnder In effetti, la versione alternativa sembra essere un golfista quando si tratta di abbinare prefissi bilanciati.
Neil,

1
Il vero scoppio avviene alla fine del gruppo, non all'inizio. Buon punto con l'alternanza per evitare il duplicato \(*però.
Martin Ender,

2

PHP, 110 108 byte

for($s=$argn;;$p?die(strtr($s,"()",")(")):$s=substr($s,1).$s[$i=0])for($p=1;$p&&$c=$s[$i++];)$p-=$c<")"?:-1;

Esegui come pipe -nRo testalo online .

abbattersi

for($s=$argn;               # import input
    ;                       # infinite loop
    $p?die(strtr($s,"()",")(")) # 2. if balanced: invert, print and exit
    :$s=substr($s,1).$s[$i=0]   #    else: rotate string, reset $i to 0
)                               # 1. test balance:
    for($p=1;                   # init $p to 1
        $p&&$c=$s[$i++];)       # loop through string while $p is >0
        $p-=$c<")"?:-1;             # increment $p for ")", decrement else


2

Ottava, 62 byte

@(s)")("(x=hankel(s,shift(s,1))-39)(all(cumsum(2*x'-3)>=0)',:)

Provalo online!

Una funzione che accetta la stringa come input e stampa tutti i risultati.

Spiegazione:

           hankel(a,shift(a,1))                                % generate a matrix of n*n where n= length(s) and its rows contain incresing circulraly shifted s
         x=...                 -39                             % convert matrix of "(" and ")" to a mtrix of 1 and 2
    ")("(x                        )                            % switch the parens
                                               2*x'-3          % convert [1 2] to [-1 1]
                                        cumsum(      )         % cumulative sum along the rows
                                    all(              >=0)'    % if all >=0
                                   (                       ,:) % extract the desired rows

2

Mathematica, 78 byte

""<>{"(",")"}[[2ToCharacterCode@#-81//.x_/;Min@Accumulate@x<0:>RotateLeft@x]]&

1

JavaScript (ES6), 97 byte

f=(s,t=s,u=t.replace(')(',''))=>u?t==u?f(s.slice(1)+s[0]):f(s,u):s.replace(/./g,c=>c<')'?')':'(')

Funziona ruotando in modo ricorsivo la stringa di input fino a quando la sua trasposizione non è bilanciata, quindi la traspone.


Semplicemente bello.
Rick Hitchcock,

1

APL (Dyalog Unicode) , 35 30 byte

Golfato un nuovo approccio grazie a @ Adám

1⌽⍣{2::01∊⍎⍕1,¨⍺}')('['()'⍳⎕]

Provalo online!

Il golf è in corso.

Spiegazione

'()'⍳⎕              Find the index of each character of the input in the string '()'
                    (this is 1-indexed, so an input of '(())()' would give 1 1 2 2 1 2)
')('[...]           Find the index of the vector in the string ')('
                    This essentially swaps ')'s with '('s and vice versa
                   On this new string, do:
 1                   rotate it one to the left
                    Until this results in 1:
 1,¨⍺                 Concatenate each element of the argument with a 1
                      This inserts 1 one before each parenthesis
                     Stringify it
                     And evaluate it, if the parentheses are balanced, this produces no errors
 1                   Check if 1 belongs to evaluated value
                      If the parentheses were not matches during ⍎, this causes a syntax error
 2::0                 This catches a syntax error and returns 0
                      Essentially this code checks if the brackets are balanced or not

0

Python 2 , 99 byte

r=[0];S=''
for c in input():b=c>'(';r+=[r[-1]+2*b-1];S+=')('[b]
n=r.index(min(r))
print S[n:]+S[:n]

Provalo online!

In forma funzionale per semplici casi di test:

Python 2 , 108 byte

def f(s):
 r=[0];S=''
 for c in s:b=c>'(';r+=[r[-1]+2*b-1];S+=')('[b]
 n=r.index(min(r))
 return S[n:]+S[:n]

Provalo online!

Questo utilizza un approccio leggermente diverso - invece di ruotare ricorsivamente la stringa, se pensiamo alle parentesi come ad incrementare e decrementare un contatore di bilanciamento, una stringa bilanciata non deve mai avere una somma totale di incrementi - decrementi inferiori a 0.

Quindi prendiamo

(()(())())

inverti le parentesi:

))())(()((

e convertilo in un elenco di somme di incrementi / decrementi:

[-1,-2,-1,-2,-3,-2,-1,-2,-1,0]

-3 è il minimo all'indice 4 (a base zero); quindi vogliamo spostarci di quell'indice + 1. Ciò garantisce che l'incremento / decremento cumulativo non sarà mai inferiore a 0; e si sommerà a 0.


Sul mio telefono, quindi non posso testarlo, ma potresti farlo r=0,invece di r=[0]?
Cyoce,

Se stai andando con @ suggerimento di Cyoce, è necessario sostituire r+=[r[-1]+2*b-1]con r+=r[-1]+2*b-1,così
OVS

0

Clojure, 118 byte

#(loop[s(map{\(\)\)\(}%)](let[s(conj(vec(rest s))(first s))](if(some neg?(reductions +(map{\( 1\) -1}s)))(recur s)s)))

Restituisce una sequenza di caratteri, quindi la definirei così:

(apply str (f "(()(())())"))
; "(()(())())"

Per prima cosa capovolge le parentesi, quindi scorre fino a quando la somma cumulativa del conteggio delle parentesi diventa negativa in qualche punto della sequenza.


0

Brainfuck , 82 byte

,[++[->->++<<]-[--->+>-<<]>-->+[-[-<<+>>>>+<<]],]+[<<]>>>[.[-]>>]<[<<]<[<<]>>[.>>]

Provalo online!

Spiegazione

Ad ogni carattere letto, un contatore viene modificato come segue:

  • Il contatore inizia da 0.
  • Dopo ogni ) , il contatore aumenta di 1.
  • Dopo ciascuna (, il contatore diminuisce di 1, a meno che il contatore non sia 0, nel qual caso il contatore rimane invariato.

Ogni prefisso è un suffisso valido di una stringa bilanciata (dopo l'inversione) se e solo se questo contatore è 0. Questo codice utilizza il prefisso più lungo per formare l'output.

,[                   Take input and start main loop
                     The cell one space right is the output cell (0 at this point),
                     and two spaces right is a copy of the previous counter value
  ++                 Add 2 to input
  [->->++<<]         Negate into output cell, and add twice to counter
  -[--->+>-<<]       Add 85 to output cell, and subtract 85 from counter
  >-->+              Subtract 2 from output cell and add 1 to counter
                     The output cell now has (81-input), and the counter has been increased by (2*input-80)
  [-[-<<+>>>>+<<]]   If the counter is nonzero, decrement and copy
,]
+[<<]                Go to the last position at which the counter is zero
>>>                  Go to following output character
[.[-]>>]             Output from here to end, clearing everything on the way
                     (Only the first one needs to be cleared, but this way takes fewer bytes)
<[<<]                Return to the same zero
<[<<]>>              Go to beginning of string
[.>>]                Output remaining characters
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.