文字列を裏返す


21

バランスの取れた文字列は、()すべての括弧を別の括弧と一致させるための括弧の文字列です。より厳密には、この文法がまたがる文字列です。

S → (S)S | ε

文字列を「裏返し」にする方法は次のとおりです。

  • (およびのすべての出現)を互いに切り替える

  • 文字列の前面から背面への文字の移動は、文字列のバランスが再び取れるまで続きます。


例を見てみましょう。

バランスの取れた文字列から始めます。

(()(())())

次に、括弧を切り替えて作成します

))())(()((

次に、文字列のバランスが取れるようになるまで、文字列の前から後ろに文字を移動します。

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

それが結果です!


一部の文字列は、複数の方法で裏返しにできることに注意してください。たとえば、文字列

(()())

裏返した場合、次のいずれかになります。

()(())

または

(())()

ただし、すべての文字列には少なくとも1つのソリューションがあります。

仕事

バランスの取れた文字列を入力および出力として使用し、その文字列を裏返しにするプログラムを作成します。複数の有効な出力が存在する可能性がある場合は、そのうちの1つだけを出力する必要があります。別のブレースタイプ(<>[]または{}必要に応じて)を使用できます。

これは競合であるため、ソースコードのサイズをバイト単位で最小化することを目指してください。

テストケース

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

常に解決策があることが保証されていますか?
ルイスメンドー

@LuisMendoはい、私はこれを証明しました。証拠を見たい場合は、チャットで私にpingを送ってください。
小麦ウィザード

ありがとう。それを知るだけで十分です。それをチャレンジに書き込む必要があるかもしれません。そうでなければ、解決策がない場合に何を出力するかを定義する必要があります
ルイスメンドー

回答:


9

ハスケル124 120 119 117 113 110 109 106 105 104 101 98バイト

bartavelleのおかげで4バイト節約!

Zgarbのおかげで3バイト節約

Peter Taylorのおかげで1バイト節約

Haskellで解決したソリューションを次に示します。その [OK]を、今私が受け取ったいくつかの助けにかなり良いおかげで、しかし、フィードバック/提案が高く評価されているので、私は、これを短くするために探しています。

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

このチェックでは、Peter Taylorからの提案のおかげで、入力のオープンペアとクローズペアが等しいと仮定しています。

gは文字列を1回回転させます。

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

その後d、単純に括弧を取り、それをミラーリングします

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

最後に、関心のある機能があります。ここでは、のpointfree表現を使用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
あなたには別のバイトを保存することができ!、あなたが最初の2例を交換して持つことができるので、文字列が開閉括弧の不均等な数を持っているケースを処理する必要がないため_!1=1<0 []!_=0<1
ピーター・テイラー

1
until短縮に使用gTIO
Zgarb

2
私が行うことでまともな貯蓄があるはずだと思うdのマップ'('(-1)すると何かを1し、その後の2最長のケースは!に組み合わせることができます(i:a)!x=a!(x+i)。最上位レベルの構造はmap d、そのuntil状態にプッシュするために再加工が必要です。実行する必要があるため、すべてを結合するために必要なコンビネーターを把握するための時間を今は持っていません。
ピーターテイラー

7

SOGL V0.1212の 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

注:10バイトの場合l{に置き換えることができますが、悲しいことに、実装されていません。


キャラクターのミラーリングは機能しますか?私はそれが何を意味するのか正確にはわかりませんが、私の直感は、それがまた機能するとは思わないキャラクターの順序を逆にすることを教えてくれます。
小麦ウィザード

1
@Olmman 文字を逆すること意図していましたが、そうではありません(ここでバイトを節約します!)。谷を変更するのはV0.13sのラインナップです。
-dzaima

5

CJam(20文字)

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

オンラインデモ

または同じ文字数

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

オンラインデモ

解剖

2つのバージョンには共通のヘッダーとフッターがあります

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バイト

(@CraigAyreのおかげで2バイト、@ PeterTaylorのおかげで2バイト、@ Shaggyのおかげで2バイト保存されました。)

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

オンラインでお試しください!リンクにはテストケースが含まれます。編集:@MartinEnderの助けを借りて8バイトを保存しました。最初の段階では括弧を単純に入れ替えますが、2番目の段階では有効なバランスの取れたプレフィックスである最長のサフィックスを探します。これは明らかに、回転が完全にバランスをとるのに十分な条件です。バランスは、バランスグループを使用して検出されます。コンストラクトは、すでに()個のsを見ている限り、((\()|(?<-4>\)))+任意の数の(sと任意の数の)sに一致します。有効なプレフィックスだけを探しているので、残りのs と一致する必要はありません。<-4>()


通常、両方の括弧を繰り返すのではなく、それらを交互に配置するだけで、byteが節約されます((\()|(?<-2>\)))。しかし、あなたの試みは私にインスピレーションを与え、さらに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の提案@と一緒に行くしている場合は、交換する必要があります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 ずつ増加します。
  • 各の後(、カウンタが0でない限り、カウンタは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.