Переверніть рядок всередину


21

Збалансований рядок - це рядок дужок, ()так що кожна дужка може бути зіставлена ​​з іншою. Більш суворо вони являють собою рядки, що охоплюються цією граматикою:

S → (S)S | ε

Ми можемо перетворити рядок "зсередини":

  • Переключення всіх подій (та )між собою

  • Переміщення символів від передньої частини струни до задньої, поки рядок знову не врівноважиться.


Давайте зробимо приклад.

Почнемо з врівноваженого рядка:

(()(())())

Потім перемикаємо паролі на створення

))())(()((

Потім перемістіть символи з передньої частини рядка до задньої частини рядка, поки рядок не врівноважиться.

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

Ось наш результат!


Зауважте, що деякі рядки можна вивернути назовні декількома способами, наприклад рядок

(()())

Якщо повернути назовні, це може бути:

()(())

або

(())()

Однак кожна рядок має щонайменше одне рішення .

Завдання

Напишіть програму, щоб взяти врівноважений рядок як вхідний і вихідний, щоб той рядок вийшов назовні. У випадках, коли може бути кілька дійсних виходів, вам потрібно вивести лише один з них. Ви можете використовувати інший тип розпірки ( <>, []або {}) , якщо ви так хочете.

Це змагання з тому ви повинні прагнути до мінімізації розміру вихідного коду, виміряного байтами.

Випробування

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

Чи гарантується, що завжди знайдеться рішення?
Луїс Мендо

@LuisMendo Так, я це довів. Якщо ви хочете побачити докази, не соромтесь надіслати мене в чаті.
Пшеничний майстер

Спасибі. Мені достатньо це знати. Можливо, вам слід вписати це в виклик, інакше вам потрібно буде визначити, що робити, якщо рішення не буде
Луїс Мендо

Відповіді:


9

Haskell , 124 120 119 117 113 110 109 106 105 104 101 98 байт

4 байти збережено завдяки бартавеллі!

3 байти збережено завдяки Zgarb

1 байт збережено завдяки Пітеру Тейлору

Ось рішення, яке я опрацював у 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

Ця перевірка передбачає, що вхід має рівну кількість відкритих і закритих парен завдяки пропозиції Пітера Тейлора.

Наступний gоберне рядок один раз.

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

Тоді ми маємо, dякий просто бере батьківську і дзеркальну

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]видалити кілька байт і вилучити паролі для d '('=')'.
bartavelle

@bartavelle Видалення паролів dвикликає помилку компілятора, повірте, я спробував. Але перша пропозиція вітається. Спасибі!
Пшеничний майстер

1
Ви можете зберегти ще один байт, !тому що вам не потрібно обробляти випадки, коли рядок має неоднакову кількість відкритих і закритих дужок, тому ви можете поміняти місцями перші два випадки і мати_!1=1<0 []!_=0<1
Пітер Тейлор

1
Використовуйте untilдля скорочення g: TIO
Zgarb

2
Я думаю , що повинна бути гідною економії, зробивши dкарту '('на (-1)і що - небудь ще 1, а потім дві довгі випадки !можуть бути об'єднані (i:a)!x=a!(x+i). Тоді структура верхнього рівня потребує переробки, щоб перейти map dв untilстан, і я маю запуститись, щоб у мене зараз не було часу, щоб зрозуміти, які комбінатори потрібно склеїти.
Пітер Тейлор

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

проти

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

Безголівки:

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 38 байт

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

Спробуйте в Інтернеті! Посилання включає тестові випадки. Редагувати: збережено 8 байт за допомогою @MartinEnder. Перший етап просто переміщує дужки, тоді як другий етап шукає найдовший суфікс, що є дійсним збалансованим префіксом, що, очевидно, є достатньою умовою для повного врівноваження обертання. Балансування виявляється за допомогою балансуючих груп. Конструкція ((\()|(?<-4>\)))+відповідає будь-якій кількості (s плюс будь-якій кількості )s, якщо ми вже <-4>бачили стільки (s. Оскільки ми шукаємо лише дійсний префікс, нам не потрібно відповідати решти )s.


Зазвичай, замість того, щоб повторювати обидві дужки, ви просто ставите їх на чергування, що зберігає байт ((\()|(?<-2>\))). Але ваша спроба просто надихнув мене , щоб знайти абсолютно новий підхід , який дозволяє економити ще два: (?<-1>(\()*\))+. Це, безумовно, стане в нагоді в майбутньому, тому дякую. :)
Мартін Ендер

Ще коротше визначити обертання, зіставивши перший суфікс, за допомогою якого можна дійти до кінця рядка, не отримуючи негативної глибини стека: tio.run/…
Martin Ender

@MartinEnder Я спочатку спробував чергування, але в той час я не міг змусити його працювати, але я не розумію, як це (?<-1>(\()*\))+працює, оскільки, схоже, хочеться вискочити зі 1стека, перш ніж насправді щось відповідати ...
Ніл

@MartinEnder Як це трапляється, версія чергування, здається, є головою, коли мова йде про відповідність збалансованим префіксам.
Ніл

1
Фактичне вискакування відбувається в кінці групи, а не на початку. Хороший момент з чергуванням, щоб уникнути дублікату, \(*хоча.
Мартін Ендер

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<')'?')':'(')

Працює за допомогою рекурсивного обертання вхідного рядка, поки його транспозиція не врівноважується, а потім його переміщення.


Просто прекрасно.
Рік Хічкок

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]

Спробуйте в Інтернеті!

Для цього використовується дещо інший підхід - замість рекурсивного обертання рядка, якщо ми вважаємо, що парен збільшується і зменшує деякий лічильник балансу, то врівноважена рядок ніколи не повинна мати загальну суму приростів - зменшення, що становить менше 0.

Отже, ми беремо

(()(())())

інвертувати парони:

))())(()((

і перетворити його в список сум приростів / зменшень:

[-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,а
овс

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

мозковий ебать , 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.