เปิดสตริงภายใน


21

สตริงที่สมดุลคือสตริงของวงเล็บ()เพื่อให้ทุกวงเล็บสามารถจับคู่กับวงเล็บอื่นได้ อย่างเข้มงวดยิ่งขึ้นพวกเขาเป็นสตริงทอดโดยไวยากรณ์นี้:

S → (S)S | ε

เราสามารถเปลี่ยนสตริง "inside out" โดย:

  • สลับการเกิดขึ้นทั้งหมดของ(และ)กับแต่ละอื่น ๆ

  • การย้ายตัวละครจากด้านหน้าของสตริงไปทางด้านหลังจนกระทั่งสตริงมีความสมดุลอีกครั้ง


ให้ทำตัวอย่าง

เราเริ่มต้นด้วยสตริงที่สมดุล:

(()(())())

จากนั้นเราสลับ parens ให้เป็น

))())(()((

จากนั้นย้ายอักขระจากด้านหน้าของสตริงไปด้านหลังของสตริงจนกระทั่งสตริงมีความสมดุล

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

นั่นคือผลลัพธ์ของเรา!


โปรดทราบว่าบางสายสามารถเปิดด้านในออกได้หลายวิธีตัวอย่างเช่นสตริง

(()())

เมื่อหันด้านในออกมาสามารถเป็นได้ทั้ง:

()(())

หรือ

(())()

อย่างไรก็ตามทุกสตริงมีทางออกอย่างน้อยหนึ่งรายการ

งาน

เขียนโปรแกรมเพื่อใช้สตริงที่มีความสมดุลเป็นอินพุตและเอาต์พุตที่สตริงนั้นเปิดด้านใน ในกรณีที่อาจมีเอาต์พุตที่ถูกต้องหลายรายการคุณต้องใช้เอาต์พุตเพียงรายการเดียวเท่านั้น คุณอาจจะใช้ชนิดรั้งที่แตกต่างกัน ( <>, []หรือ{}) ดังนั้นหากคุณต้องการ

นี่คือการแข่งขันดังนั้นคุณควรตั้งเป้าหมายลดขนาดซอร์สโค้ดของคุณตามขนาดเป็นไบต์

กรณีทดสอบ

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

มันรับประกันว่าจะมีทางออกเสมอหรือไม่?
Luis Mendo

@ LuisMendo ใช่ฉันได้พิสูจน์แล้ว หากคุณต้องการดูหลักฐานคุณสามารถปิงฉันในการแชทได้
ข้าวสาลีตัวช่วยสร้าง

ขอบคุณ มันก็เพียงพอแล้วสำหรับฉันที่จะรู้ว่า บางทีคุณควรเขียนลงในความท้าทายมิฉะนั้นคุณจะต้องกำหนดสิ่งที่จะส่งออกถ้าไม่มีวิธีแก้ปัญหา
Luis Mendo

คำตอบ:


9

Haskell , 124 120 119 117 113 110 109 106 105 104 101 98 ไบต์

บันทึกได้ 4 ไบต์ด้วย bartavelle!

บันทึกได้ 3 ไบต์ด้วย Zgarb

บันทึก 1 ไบต์ขอบคุณ Peter Taylor

นี่เป็นวิธีแก้ปัญหาที่ฉันทำงานใน Haskell มันโอเคตอนนี้ค่อนข้างดีขอบคุณความช่วยเหลือที่ฉันได้รับ แต่ฉันต้องการทำให้ข้อความสั้นลงดังนั้นคำติชม / ข้อเสนอแนะจะได้รับการชื่นชม

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

ลองออนไลน์!

คำอธิบาย

โปรแกรมนี้กำหนด 4 ฟังก์ชั่นครั้งแรก(!)พิจารณาว่าสตริงมีความสมดุล มันกำหนดไว้ดังนี้:

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

การตรวจสอบนี้สันนิษฐานว่าอินพุตมีจำนวน parens ที่เปิดและปิดเท่ากันขอบคุณคำแนะนำจาก Peter Taylor

ถัดไปgจะหมุนสตริงหนึ่งครั้ง

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

จากนั้นเราก็มีdที่จะใช้เพียงแค่ paren และสะท้อนมัน

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

ในที่สุดเราก็มีฟังก์ชั่นที่เรากังวล ที่นี่เราใช้การแสดงแบบไร้จุดuntil(!0)gซึ่งประกอบกับmap dซึ่งแม็พdกับอินพุตและนำgไปใช้จนกระทั่งผลลัพธ์มีความสมดุล นี่เป็นกระบวนการที่แน่นอนที่อธิบายไว้ในคำถาม

until(!0)g.map d

1
คุณสามารถเศษไม่กี่ไบต์ที่มีg x@(a:b)|x!0=x|1>0=g$b++[a]และลบ parens d '('=')'สำหรับ
bartavelle

@bartavelle การลบ parens สำหรับdสาเหตุข้อผิดพลาดของคอมไพเลอร์เชื่อว่าฉันได้ลองแล้ว แต่ข้อเสนอแนะแรกคือยินดีต้อนรับ ขอบคุณ!
ข้าวสาลีตัวช่วยสร้าง

1
คุณสามารถบันทึกไบต์อื่นได้!เนื่องจากคุณไม่จำเป็นต้องจัดการกับกรณีที่สตริงมีจำนวนวงเล็บเปิดและปิดที่ไม่เท่ากันดังนั้นคุณสามารถสลับสองกรณีแรกและมี_!1=1<0 []!_=0<1
Peter Taylor

1
ใช้untilเพื่อย่อg: TIO
Zgarb

2
ผมคิดว่าควรจะมีการประหยัดที่ดีโดยการทำdแผนที่'('การ(-1)และสิ่งอื่น ๆ ที่จะ1แล้วสองกรณีที่ยาวที่สุดของสามารถรวมกันเพื่อ! (i:a)!x=a!(x+i)โครงสร้างระดับบนสุดจำเป็นต้องมีการทำงานซ้ำเพื่อผลักดันให้map dเข้าสู่untilสภาวะและฉันต้องวิ่งดังนั้นฉันจึงไม่ได้มีเวลาพอที่จะคิดได้ว่า combinators ใดที่จำเป็นในการรวมกาวเข้าด้วยกัน
Peter Taylor

7

SOGL V0.12 , 12 11 ไบต์

↔]»:l{Ƨ()øŗ

ลองที่นี่!

คำอธิบาย:

↔            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{สามารถแทนที่ด้วย(สำหรับ 10 ไบต์ แต่น่าเสียดายที่มันไม่ได้ถูกนำไปใช้


คุณแน่ใจหรือว่าการสะท้อนถึงตัวละครใช้งานได้? ฉันไม่รู้เหมือนกันว่ามันหมายถึงอะไร แต่สัญชาตญาณของฉันบอกฉันว่ามันตรงกันข้ามกับลำดับของตัวละครที่ฉันไม่คิดว่าจะได้ผล
ข้าวสาลีตัวช่วยสร้าง

1
@Olmman มันถูกตั้งใจที่จะกลับตัวละคร แต่ไม่ได้ (ซึ่งจะช่วยประหยัดไบต์ที่นี่!) อยู่ในรุ่น V0.13s เพื่อเปลี่ยนราง ตัวอย่าง
dzaima

5

CJam (20 ตัวอักษร)

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

การสาธิตออนไลน์

หรือสำหรับจำนวนถ่านเดียวกัน

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

การสาธิตออนไลน์

การผ่า

ทั้งสองเวอร์ชันมีส่วนหัวและส่วนท้ายร่วม

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

จากนั้นบิตที่อยู่ตรงกลางจะคำนวณว่าต้องหมุนเท่าไร ทั้งคู่ใช้การประเมินผลและพึ่งพา(การเป็นผู้ดำเนินการลดค่า CJam และ)เป็นผู้ดำเนินการส่วนเพิ่ม

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 ไบต์

(บันทึก 2 ไบต์ขอบคุณ @CraigAyre, 2 ไบต์ขอบคุณ @PeterTaylor, 2 ไบต์ขอบคุณ @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``
)

กรณีทดสอบ:


3

เรติน่า46 46ไบต์

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

ลองออนไลน์! ลิงค์มีกรณีทดสอบ แก้ไข: บันทึก 8 ไบต์ด้วยความช่วยเหลือจาก @MartinEnder ขั้นตอนแรกเพียงแค่สลับวงเล็บในขณะที่ขั้นตอนที่สองมองหาคำต่อท้ายที่ยาวที่สุดซึ่งเป็นคำนำหน้าสมดุลที่ถูกต้องซึ่งเห็นได้ชัดว่าเป็นเงื่อนไขที่เพียงพอสำหรับการหมุนให้มีความสมดุลอย่างเต็มที่ ตรวจพบการทรงตัวโดยใช้กลุ่มการทรงตัว สร้าง((\()|(?<-4>\)))+ตรงกับจำนวนใด ๆ(s บวกจำนวนใด ๆ)s ตราบใดที่เรามีอยู่แล้ว ( <-4>) เห็นเป็นจำนวนมาก(s เนื่องจากเราเพียงมองหาคำนำหน้าถูกต้องเราไม่ได้มีเพื่อให้ตรงกับส่วนที่เหลือ)ของ


((\()|(?<-2>\)))ปกติแทนการทำซ้ำทั้งวงเล็บคุณเพียงแค่ใส่พวกเขาในการสลับกันซึ่งจะช่วยประหยัดไบต์ (?<-1>(\()*\))+แต่ความพยายามของคุณเพียงแค่แรงบันดาลใจที่จะหาวิธีการใหม่ที่สมบูรณ์แบบที่จะช่วยประหยัดอีกสอง: สิ่งนี้จะมีประโยชน์ในอนาคตอย่างแน่นอนดังนั้นขอขอบคุณ :)
Martin Ender

มันสั้นยิ่งกว่านี้เพื่อกำหนดการหมุนโดยการจับคู่คำต่อท้ายแรกซึ่งคุณสามารถไปถึงจุดสิ้นสุดของสตริงโดยไม่ได้รับความลึกของกองซ้อน: tio.run/…
Martin Ender

@MartinEnder ฉันพยายามสลับกัน แต่ฉันไม่สามารถทำงานได้ในเวลานั้น แต่ฉันล้มเหลวที่จะดูว่า(?<-1>(\()*\))+มันใช้งานได้ดีแค่ไหนเนื่องจากดูเหมือนว่าจะต้องการป๊อปอัพจาก1สแต็กก่อนที่จะจับคู่อะไร ...
Neil

@MartinEnder เมื่อมันเกิดขึ้นรุ่นสำรองดูเหมือนจะเป็นนักกอล์ฟเมื่อมันมาถึงการจับคู่คำนำหน้าแบบสมดุล
Neil

1
การ popping จริงเกิดขึ้นที่ส่วนท้ายของกลุ่มไม่ใช่จุดเริ่มต้น จุดที่ดีกับการสลับเพื่อหลีกเลี่ยงการซ้ำ\(*แม้ว่า
Martin Ender

2

PHP, 110 108 ไบต์

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

ทำงานเป็นท่อที่มี-nRหรือทดสอบออนไลน์

ทำให้พังถล่ม

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

อ็อกเทฟ 62 ไบต์

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

ลองออนไลน์!

ฟังก์ชันที่รับสตริงเป็นอินพุตและพิมพ์ผลลัพธ์ทั้งหมด

คำอธิบาย:

           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


1

JavaScript (ES6), 97 ไบต์

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

ทำงานโดยหมุนวนสายป้อนข้อมูลซ้ำจนกระทั่งการถ่ายโอนนั้นมีความสมดุลจากนั้นทำการแปลง


สวยเรียบง่าย
Rick Hitchcock

1

APL (Dyalog Unicode) , 35 30 ไบต์

เปลี่ยนแนวทางใหม่ด้วย @ Adám

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

ลองออนไลน์!

กำลังเล่นกอล์ฟอยู่

คำอธิบาย

'()'⍳⎕              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 ไบต์

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]

ลองออนไลน์!

ในรูปแบบฟังก์ชั่นสำหรับกรณีทดสอบง่าย ๆ :

Python 2 , 108 ไบต์

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]

ลองออนไลน์!

วิธีนี้ใช้วิธีที่แตกต่างกันเล็กน้อย - แทนที่จะหมุนวนซ้ำถ้าเราคิดว่า parens เป็นการเพิ่มและลดจำนวนตัวนับจำนวนคงเหลือสตริงที่สมดุลจะต้องไม่มีผลรวมของการเพิ่ม - การลดที่น้อยกว่า 0

ดังนั้นเราจึง

(()(())())

กลับส่วน parens:

))())(()((

และแปลงเป็นรายการผลรวมของส่วนเพิ่ม / ลดลง:

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

-3 คือค่าต่ำสุดที่ดัชนี 4 (อิงตามศูนย์); ดังนั้นเราจึงต้องการเลื่อนตามดัชนี + 1 สิ่งนี้รับประกันได้ว่าการเพิ่ม / ลดยอดสะสมจะไม่น้อยกว่า 0 และจะรวมเป็น 0


บนโทรศัพท์ของฉันดังนั้นฉันไม่สามารถทดสอบได้ แต่คุณสามารถทำr=0,แทนได้r=[0]หรือไม่
Cyoce

หากคุณกำลังจะมีข้อเสนอแนะ @ Cyoce ของคุณจะต้องเปลี่ยนr+=[r[-1]+2*b-1]ด้วยr+=r[-1]+2*b-1,เช่นกัน
OVS

0

Clojure 118 ไบต์

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

ส่งกลับลำดับของตัวละครดังนั้นฉันจะเรียกมันว่า:

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

วงเล็บแรกพลิกแล้ววนซ้ำตราบใดที่ผลรวมสะสมของจำนวนวงเล็บไปทางลบในบางจุดของลำดับ


0

brainfuck , 82 ไบต์

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

ลองออนไลน์!

คำอธิบาย

เมื่ออ่านอักขระแต่ละตัวตัวนับจะถูกปรับเปลี่ยนดังนี้:

  • ตัวนับเริ่มต้นที่ 0
  • หลังจากแต่ละ)ตัวนับเพิ่มขึ้น 1
  • หลังจากแต่ละ(ตัวนับลดลง 1 เว้นแต่ว่าตัวนับเป็น 0 ซึ่งในกรณีนี้ตัวนับจะไม่เปลี่ยนแปลง

แต่ละคำนำหน้าเป็นคำต่อท้ายที่ถูกต้องของสตริงที่สมดุล (หลังการผกผัน) ถ้าเพียงถ้าเคาน์เตอร์นี้เป็น 0 รหัสนี้ใช้คำนำหน้าดังกล่าวที่ยาวที่สุดในการสร้างรูปแบบเอาท์พุท

,[                   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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.