Bir dize ters çevirin


21

Dengeli bir dize parantez dizisidir, ()böylece her parantez başka biriyle eşleştirilebilir. Daha titizlikle bu dilbilgisi tarafından yayılan dizelerdir:

S → (S)S | ε

Bir dizgiyi "tersyüz" olarak çevirebiliriz:

  • Tüm oluşumlarını (ve )birbirleriyle geçişi

  • Karakterleri dizenin önünden arkaya doğru hareket ettirerek dizenin tekrar dengelenmesini sağlayın.


Bir örnek yapalım.

Dengeli dizeyle başlarız:

(()(())())

Daha sonra yapmak için parenler değiştiririz

))())(()((

Ardından, karakterleri dizenin önünden, dizenin dengesine gelene kadar dizenin arkasına taşıyın.

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

Bizim sonucumuz bu!


Bazı dizgilerin, örneğin dize gibi birçok yolla ters çevrilebileceğini unutmayın.

(()())

Tersyüz edildiğinde şunlardan biri olabilir:

()(())

veya

(())()

Ancak her dize en az bir çözüme sahiptir .

Görev

Dengeli bir dizgiyi girdi ve çıktı olarak almak için bir program yazınız. Birden fazla geçerli çıkışın olabileceği durumlarda, bunlardan sadece bir tanesine ihtiyacınız vardır. İsterseniz farklı bir ayraç tipi ( <>, []veya {}) kullanabilirsiniz.

Bu bir yarışmasıdır, bu nedenle kaynak kodunuzun boyutunu bayt olarak ölçtüğünüz en aza indirmeyi hedeflemelisiniz.

Test Kılıfları

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

Her zaman bir çözüm olduğu garantili midir?
Luis Mendo,

@LuisMendo Evet, bunu kanıtladım. Eğer kanıtı görmek istersen, sohbete beni atmaktan çekinme.
Buğday Sihirbazı

Teşekkürler. Bunu bilmek benim için yeterli. Belki de zorluğun içine yazmalısın, aksi halde çözüm yoksa ne çıktısını tanımlaman gerekir
Luis Mendo

Yanıtlar:


9

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

Bartavelle sayesinde 4 bayt kurtarıldı!

Zgarb sayesinde 3 bayt kurtarıldı

Peter Taylor sayesinde 1 bayt kurtarıldı

İşte Haskell'de çalıştığım bir çözüm. Onun Tamam şimdi sağ aldığım bazı yardımına oldukça iyi teşekkürler ama geri bildirim / önerileri takdir edilmektedir, böylece bu kısaltmak için arıyorum.

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 _='('

Çevrimiçi deneyin!

açıklama

Bu program 4 fonksiyon tanımlar, ilk (!)dize dengede olup olmadığını belirler. Aşağıdaki gibi tanımlanır:

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

Bu kontrol, Peter Taylor'un önerisi sayesinde girişin eşit sayıda açık ve kapalı paren olduğunu varsaymaktadır.

Bir sonraki gdize bir kez dönecek.

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

Sonra dbasitçe bir paren alır ve onu yansıtır.

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

Sonunda ilgilendiğimiz işleve sahibiz. Burada , girdi ile eşleştirilen ve sonuç dengelenene kadar geçerli until(!0)golan map d, noktasuz bir gösterimi kullanırız . Bu, soruda açıklanan kesin işlemdir.dg

until(!0)g.map d

1
g x@(a:b)|x!0=x|1>0=g$b++[a]Için parens ve kaldırarak birkaç bayt hurda edebilirsiniz d '('=')'.
bartavelle

@bartavelle parens için dbir derleyici hatasına neden oluyor, inanıyorum ki bana. Ancak ilk öneri kabul edilir. Teşekkürler!
Buğday Sihirbazı

1
!Dizenin eşit olmayan sayıda açık ve kapalı parantez içerdiği durumlarda işlem yapmanız gerekmediğinden başka bir baytı kaydedebilirsiniz , bu nedenle ilk iki vakayı değiştirebilir ve sahip olabilirsiniz_!1=1<0 []!_=0<1
Peter Taylor

1
untilKısaltmak için kullanın g: TIO
Zgarb

2
Ben yaparak iyi bir tasarruf olması gerektiğini düşünüyorum dharita '('için (-1)ve başka bir şey 1, ve daha sonra iki uzun vakalar !için kombine edilebilir (i:a)!x=a!(x+i). Üst düzey yapısı daha sonra itmek üstünde yeniden ihtiyacı map diçine untilkoşulu ve ben combinators hepsi birbirlerine yapıştırmak için gerekli olan ne şekle şu anda zamanım yok bu yüzden çalıştırmak zorunda.
Peter Taylor

7

SOGL V0.12 , 12 11 bayt

↔]»:l{Ƨ()øŗ

Burada dene!

Açıklama:

↔            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

Not: ( 10 bayt için) l{ile değiştirilebilir , ancak ne yazık ki uygulanmadı.


Karakterleri yansıtmanın işe yaradığından emin misiniz? Bunun ne anlama geldiğini tam olarak bilmiyorum ama sezgim, aynı zamanda işe yarayacağını sanmıyorum karakterlerin sırasını da tersine çevirdiğini söylüyor.
Buğday Sihirbazı,

1
@Olmman O edildi karakterleri tersine çevirmek için tasarlanmıştır, ancak değil (burada bir byte kazandırır!). Tekneyi değiştirmek için V0.13s programında. Örnek
dzaima

5

CJam (20 karakter)

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

Çevrimiçi demo

veya aynı karakter sayısı için

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

Çevrimiçi demo

teşrih

İki versiyonun ortak bir üstbilgisi ve altbilgisi var.

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

Sonra ortadaki bit açıkça ne kadar dönmesi gerektiğini hesaplar. Her ikisi de değerlendirme kullanıyor ve (CJam azaltma operatörü ve )artırma operatörü olmaya güveniyor .

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 bayt

(@CraigAyre sayesinde 2 bayt, @PeterTaylor sayesinde 2 bayt, @Shaggy sayesinde 2 bayt kaydedildi.)

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

Test durumları:


3

Retina , 46 38 bayt

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

Çevrimiçi deneyin! Link, test durumlarını içerir. Düzenleme: @MartinEnder yardımı ile 8 bayt kaydedildi. İlk aşama parantezleri basitçe dönüştürürken, ikinci aşama ise rotasyonun tam olarak dengelenmesi için yeterli bir koşul olan geçerli bir dengeli ön ek olan en uzun son eki arar. Dengeleme, dengeleme grupları kullanılarak tespit edilir. Yapı , çok sayıda s olarak gördüğümüz sürece ( s) herhangi bir sayı s artı herhangi bir sayı s ile ((\()|(?<-4>\)))+eşleşir . Yalnızca geçerli bir önek aradığımız için kalanları eşleştirmek zorunda değiliz .()<-4>()


Normal olarak, her iki parantezi tekrarlamak yerine, onları sadece bir bayttan tasarruf eden bir alternatife koyarsınız ((\()|(?<-2>\))). Ama girişimi sadece başka iki kaydeder tamamen yeni bir yaklaşım bulmak için bana ilham: (?<-1>(\()*\))+. Bu kesinlikle gelecekte işe yarayacak, teşekkür ederim. :)
Martin Ender

Negatif bir yığın derinliği elde etmeden dizenin sonuna ulaşabileceğiniz ilk son eki eşleştirerek dönüşü belirlemek daha da kısadır: tio.run/…
Martin Ender

@MartinEnder Ben aslında bir değişim denedim ama o zaman işe almak için alamadım, ama aslında nasıl bir şey eşleşmeden önce yığından patlamak (?<-1>(\()*\))+istiyorum gibi görünüyor, ben bile nasıl çalıştığını göremiyorum 1...
Neil

@MartinEnder Olduğu gibi, dönüşümlü sürüm öneki dengeli öneklere gelince golfçü görünüyor.
Neil,

1
Gerçek patlama, başlangıçta değil grubun sonunda gerçekleşir. Yinelemekten kaçınmak için alternatif ile iyi bir nokta \(*.
Martin Ender

2

PHP, 110 108 bayt

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

Boru olarak çalıştırın -nRveya çevrimiçi olarak test edin .

Yıkmak

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

Oktav, 62 bayt

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

Çevrimiçi deneyin!

Dizeyi girdi olarak alan ve tüm sonuçları basan bir işlev.

Açıklama:

           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 bayt

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

1

JavaScript (ES6), 97 bayt

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

Giriş dizesini, transpoze dengelenene kadar tekrarlı bir şekilde döndürerek ve ardından onu transpoze ederek çalışır.


Sadece güzel.
Rick Hitchcock

1

APL (Dyalog Unicode) , 35 30 bayt

@ Adám sayesinde yeni bir yaklaşım benimsendi

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

Çevrimiçi deneyin!

Golf devam ediyor.

açıklama

'()'⍳⎕              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 bayt

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]

Çevrimiçi deneyin!

Kolay test durumları için fonksiyon biçiminde:

Python 2 , 108 bayt

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]

Çevrimiçi deneyin!

Bu biraz farklı bir yaklaşım kullanır - ipi tekrar tekrar döndürmek yerine, eğer parenlerin bir denge sayacını artırma ve azaltma olduğunu düşünürsek, o zaman dengeli bir dize asla toplam bir artış toplamına sahip olmamalıdır - 0'dan daha az olan azalmalar.

Biz alırız

(()(())())

parens'i ters çevir:

))())(()((

ve bunu artan / azalışların bir listesine dönüştürün:

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

-3, dizin 4'teki minimumdur (sıfır temelli); bu yüzden bu indeks + 1'e geçmek istiyoruz. Bu, birikimli artışın / azalmanın asla 0'dan az olmayacağını garanti eder; ve 0 toplayacaktır.


Telefonumda test edemiyorum ama r=0,yerine yapabilir misin r=[0]?
Cyoce

Eğer Cyoce önerisine @ ile gidiyoruz, değiştirmek gerekecektir r+=[r[-1]+2*b-1]ile r+=r[-1]+2*b-1,de
ovs

0

Clojure, 118 bayt

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

Bir karakter dizisi döndürür, bu yüzden şöyle söylerim:

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

İlk önce parantezleri döndürür, sonra da parantez sayısının kümülatif toplamı, dizinin bir noktasında negatif olduğu sürece döngüler.


0

brainfuck , 82 bayt

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

Çevrimiçi deneyin!

açıklama

Her karakter okunurken, bir sayaç aşağıdaki gibi değiştirilir:

  • Sayaç 0'dan başlar.
  • Her birinden sonra ), sayaç 1 artar.
  • Her birinden sonra (, sayaç 0 olmadıkça sayaç 1 azalır, bu durumda sayaç değişmez.

Her önek, yalnızca ve bu sayaç 0 ise (ters çevrmeden sonra) dengeli bir dizgenin geçerli bir sonekidir. Bu kod çıktıyı oluşturmak için en uzun ön eki kullanır.

,[                   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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.