Xoay một chuỗi từ trong ra ngoài


21

Chuỗi cân bằng là một chuỗi các dấu ngoặc đơn ()để mọi dấu ngoặc đơn có thể được khớp với một chuỗi khác. Nghiêm khắc hơn, chúng là các chuỗi được kéo dài bởi ngữ pháp này:

S → (S)S | ε

Chúng ta có thể biến một chuỗi "từ trong ra ngoài" bằng cách:

  • Chuyển đổi tất cả các lần xuất hiện ()với nhau

  • Di chuyển các ký tự từ phía trước của chuỗi sang phía sau cho đến khi chuỗi được cân bằng lại.


Hãy làm một ví dụ.

Chúng tôi bắt đầu với chuỗi cân bằng:

(()(())())

Sau đó chúng tôi chuyển đổi parens để thực hiện

))())(()((

Sau đó di chuyển các ký tự từ phía trước chuỗi sang phía sau chuỗi cho đến khi chuỗi được cân bằng.

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

Đó là kết quả của chúng tôi!


Lưu ý rằng một số chuỗi có thể được bật ra ngoài theo nhiều cách, ví dụ như chuỗi

(()())

Khi bật ra ngoài có thể là:

()(())

hoặc là

(())()

Tuy nhiên, mỗi chuỗi có ít nhất một giải pháp .

Bài tập

Viết chương trình lấy chuỗi cân bằng làm đầu vào và đầu ra chuỗi đó bật ra ngoài. Trong trường hợp có thể có nhiều đầu ra hợp lệ, bạn chỉ cần xuất một trong số chúng. Bạn có thể sử dụng một loại cú đúp khác nhau ( <>, []hoặc {}) nếu bạn rất muốn.

Đây là một cuộc thi vì vậy bạn nên cố gắng giảm thiểu kích thước mã nguồn của mình, được đo bằng byte.

Các trường hợp thử nghiệm

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

Có đảm bảo rằng luôn luôn có một giải pháp?
Luis Mendo

@LuisMendo Vâng, tôi đã chứng minh điều này. Nếu bạn muốn xem bằng chứng, vui lòng ping tôi trong trò chuyện.
Phù thủy lúa mì

Cảm ơn. Nó là đủ cho tôi để biết rằng. Có lẽ bạn nên viết nó vào thử thách, nếu không bạn sẽ cần xác định đầu ra là gì nếu không có giải pháp
Luis Mendo

Câu trả lời:


9

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

4 byte được lưu nhờ bartavelle!

3 byte được lưu nhờ Zgarb

Lưu 1 byte nhờ Peter Taylor

Đây là một giải pháp tôi đã thực hiện ở Haskell. Nó đúng ok bây giờ nhờ khá tốt đối với một số giúp đỡ tôi nhận được, nhưng tôi đang tìm cách để làm cho điều này ngắn hơn, vì vậy thông tin phản hồi / đề xuất được đánh giá cao.

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

Hãy thử trực tuyến!

Giải trình

Chương trình này xác định 4 hàm, đầu tiên (!)xác định nếu một chuỗi được cân bằng. Nó được định nghĩa như sau:

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

Kiểm tra này giả định rằng đầu vào có số lần mở và đóng bằng nhau nhờ một gợi ý từ Peter Taylor.

Tiếp theo gsẽ xoay chuỗi một lần.

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

Sau đó chúng tôi có d mà chỉ cần lấy một paren và phản chiếu nó

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

Cuối cùng chúng ta có chức năng mà chúng ta quan tâm. Ở đây chúng tôi sử dụng một biểu diễn không có điểm until(!0)gbao gồm map d, ánh xạ dtới đầu vào và áp dụng gcho đến khi kết quả được cân bằng. Đây là quá trình chính xác được mô tả trong câu hỏi.

until(!0)g.map d

1
Bạn có thể loại bỏ một vài byte với g x@(a:b)|x!0=x|1>0=g$b++[a]và loại bỏ các parens cho d '('=')'.
bartavelle

@bartavelle Loại bỏ các parens vì dgây ra lỗi trình biên dịch, hãy tin tôi đã thử. Nhưng đề nghị đầu tiên được chào đón. Cảm ơn!
Phù thủy lúa mì

1
Bạn có thể lưu một byte khác !vì bạn không cần phải xử lý các trường hợp trong đó chuỗi có số lượng dấu ngoặc mở và đóng không bằng nhau, vì vậy bạn có thể trao đổi hai trường hợp đầu tiên và có_!1=1<0 []!_=0<1
Peter Taylor

1
Sử dụng untilđể rút ngắn g: TIO
Zgarb

2
Tôi nghĩ cần có một tiết kiệm khá bằng cách làm cho dbản đồ '('để (-1)và bất cứ điều gì khác để 1, và sau đó là hai trường hợp dài nhất !có thể được kết hợp để (i:a)!x=a!(x+i). Cấu trúc cấp cao nhất sau đó cần làm lại để đẩy map dvào untilđiều kiện và tôi phải chạy để tôi không có thời gian ngay bây giờ để tìm ra những tổ hợp nào được yêu cầu để dán tất cả lại với nhau.
Peter Taylor

7

SOGL V0.12 , 12 11 byte

↔]»:l{Ƨ()øŗ

Hãy thử nó ở đây!

Giải trình:

↔            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

Lưu ý: l{có thể được thay thế bằng ( cho 10 byte, nhưng thật đáng buồn, nó không được thực hiện.


Bạn có chắc chắn rằng phản chiếu các nhân vật hoạt động? Tôi không biết chính xác điều đó có nghĩa là gì nhưng trực giác của tôi nói với tôi rằng nó cũng đảo ngược thứ tự của các nhân vật mà tôi không nghĩ sẽ hoạt động.
Phù thủy lúa mì

1
@Olmman Nó được dùng để đảo ngược các ký tự, nhưng không (giúp tiết kiệm một byte ở đây!). Đó là trên dòng V0.13s để thay đổi máng. Ví dụ
dzaima

5

CJam (20 ký tự)

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

Bản demo trực tuyến

hoặc cho cùng một số char

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

Bản demo trực tuyến

Mổ xẻ

Hai phiên bản có một tiêu đề và chân trang chung

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

Sau đó, bit ở giữa rõ ràng sẽ tính toán mức độ cần thiết để xoay. Cả hai đều sử dụng đánh giá và dựa vào (việc là toán tử giảm giá của CJam và )là toán tử gia tăng.

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

đấu với

_,,     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

(Đã lưu 2 byte nhờ @CraigAyre, 2 byte nhờ @PeterTaylor, 2 byte nhờ @Shaggy.)

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

Ung dung:

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

Các trường hợp thử nghiệm:


3

Võng mạc , 46 38 byte

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

Hãy thử trực tuyến! Liên kết bao gồm các trường hợp thử nghiệm. Chỉnh sửa: Đã lưu 8 byte với sự trợ giúp từ @MartinEnder. Giai đoạn đầu tiên chỉ đơn giản là chuyển các dấu ngoặc đơn, trong khi giai đoạn thứ hai tìm hậu tố dài nhất đó là tiền tố cân bằng hợp lệ, rõ ràng là điều kiện đủ để xoay vòng được cân bằng hoàn toàn. Sự cân bằng được phát hiện bằng cách sử dụng các nhóm cân bằng. Cấu trúc ((\()|(?<-4>\)))+khớp với bất kỳ số (s nào cộng với bất kỳ số )s nào miễn là chúng ta đã ( <-4>) thấy nhiều (s. Vì chúng tôi chỉ tìm kiếm một tiền tố hợp lệ, chúng tôi không phải khớp với các )s còn lại .


Thông thường, thay vì lặp lại cả hai dấu ngoặc đơn, bạn chỉ cần đặt chúng trong một xen kẽ, sẽ tiết kiệm một byte ((\()|(?<-2>\))). Nhưng nỗ lực của bạn chỉ truyền cảm hứng cho tôi để tìm ra một cách tiếp cận hoàn toàn mới để cứu hai người khác : (?<-1>(\()*\))+. Điều này chắc chắn sẽ có ích trong tương lai, vì vậy cảm ơn bạn. :)
Martin Ender

Thậm chí còn ngắn hơn để xác định xoay vòng bằng cách khớp với hậu tố đầu tiên mà qua đó bạn có thể đến cuối chuỗi mà không nhận được độ sâu ngăn xếp âm: tio.run/ Kẻ
Martin Ender

@MartinEnder Ban đầu tôi đã thử một sự thay thế nhưng tôi không thể làm cho nó hoạt động vào thời điểm đó, nhưng tôi không thấy nó (?<-1>(\()*\))+hoạt động như thế nào , vì nó dường như muốn bật ra khỏi 1ngăn xếp trước khi thực sự khớp với bất cứ điều gì ...
Neil

@MartinEnder Khi điều đó xảy ra, phiên bản thay thế dường như trở nên golfer hơn khi phù hợp với các tiền tố cân bằng.
Neil

1
Popping thực tế xảy ra ở cuối nhóm, không phải bắt đầu. Điểm tốt với sự xen kẽ để tránh trùng lặp \(*mặc dù.
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;

Chạy như ống với -nRhoặc kiểm tra nó trực tuyến .

phá vỡ

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

Octave, 62 byte

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

Hãy thử trực tuyến!

Một hàm lấy chuỗi làm đầu vào và in tất cả các kết quả.

Giải trình:

           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

Toán học, 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<')'?')':'(')

Hoạt động bằng cách xoay đệ quy chuỗi đầu vào cho đến khi chuyển vị của nó được cân bằng, sau đó hoán vị nó.


Đơn giản là đẹp.
Rick Hitchcock

1

APL (Unicode Dy) , 35 30 byte

Chơi gôn một cách tiếp cận mới nhờ @ Adám

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

Hãy thử trực tuyến!

Chơi golf đang được tiến hành.

Giải trình

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

Hãy thử trực tuyến!

Ở dạng hàm cho các trường hợp kiểm tra dễ dàng:

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]

Hãy thử trực tuyến!

Điều này sử dụng một cách tiếp cận hơi khác - thay vì xoay vòng theo cách đệ quy, nếu chúng ta nghĩ về các phép tính như tăng và giảm một số bộ đếm cân bằng, thì một chuỗi cân bằng không bao giờ có tổng số gia tăng - các số giảm nhỏ hơn 0.

Vì vậy, chúng tôi lấy

(()(())())

đảo ngược các parens:

))())(()((

và chuyển đổi nó thành một danh sách các khoản tăng / giảm:

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

-3 là mức tối thiểu tại chỉ số 4 (không dựa trên); vì vậy chúng tôi muốn thay đổi theo chỉ số đó + 1. Điều này đảm bảo rằng mức tăng / giảm tích lũy sẽ không bao giờ nhỏ hơn 0; và sẽ tổng bằng 0.


Trên điện thoại của tôi để tôi không thể kiểm tra, nhưng bạn có thể làm r=0,thay thế r=[0]không?
Cyoce

Nếu bạn đang đi với @ đề nghị Cyoce, bạn sẽ cần phải thay thế r+=[r[-1]+2*b-1]với r+=r[-1]+2*b-1,cũng
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)))

Trả về một chuỗi các ký tự, vì vậy tôi gọi nó như thế này:

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

Đầu tiên lật dấu ngoặc, sau đó lặp lại miễn là tổng tích lũy của số đếm khung sẽ âm ở một số điểm của chuỗi.


0

Brainfuck , 82 byte

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

Hãy thử trực tuyến!

Giải trình

Với mỗi ký tự được đọc, một bộ đếm được sửa đổi như sau:

  • Bộ đếm bắt đầu từ 0.
  • Sau mỗi cái ) , bộ đếm tăng thêm 1.
  • Sau mỗi lần (, bộ đếm giảm đi 1, trừ khi bộ đếm bằng 0, trong trường hợp đó bộ đếm không đổi.

Mỗi tiền tố là một hậu tố hợp lệ của một chuỗi cân bằng (sau khi đảo ngược) khi và chỉ khi bộ đếm này bằng 0. Mã này sử dụng tiền tố dài nhất như vậy để tạo đầu ra.

,[                   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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.