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::0⋄1∊⍎⍕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.