Golf A括号匹配算法


25

您将得到一个字符串s。保证字符串具有相等的且至少为[s和]s。还可以保证括号是平衡的。该字符串也可以包含其他字符。

目的是输出/返回元组列表或包含每个[]对的索引的列表列表。

注意:字符串为零索引。

示例: !^45sdfd[hello world[[djfut]%%357]sr[jf]s][srtdg][]应返回

[(8, 41), (20, 33), (21, 27), (36, 39), (42, 48), (49, 50)]或与此等效的东西。元组不是必需的。列表也可以使用。

测试用例:

input:[[asdf][][td([)ty54g% ]hg[[f]u][f[[jhg][gfd]sdf]sdfs]ghd]fr43f]
output:[(0, 62),(1, 6), (7, 8), (9, 56), (13, 22), (25, 30), (26, 28), (31, 52), (33, 47), (34, 38), (39, 43)]
input:[[][][][]][[][][][[[[(]]]]]))
output:[(0, 9), (1, 2), (3, 4), (5, 6), (7, 8), (10,26),(11, 12), (13, 14), (15, 16), (17, 25), (18, 24), (19, 23), (20, 22)]
input:[][][[]]
output:[(0, 1), (2, 3), (4, 7), (5, 6)]
input:[[[[[asd]as]sd]df]fgf][][]
output:[(0, 21), (1, 17), (2, 14), (3, 11), (4, 8), (22, 23), (24, 25)]
input:[]
output:[(0,1)]
input:[[(])]
output:[(0, 5), (1, 3)]

这是,因此每种编程语言的最短代码(以字节为单位)获胜。


1
输出顺序重要吗?
wastl

1
不,不是的。
风车饼干

21
“注意:字符串是零索引的。” -非常常见的是,允许实施人员在此类挑战中选择一致的索引(但这当然要取决于您)
Jonathan Allan

1
我们可以将输入作为字符数组吗?
粗野的

7
花费

Answers:


13

Brain-Flak Classic,108字节

{((((((([][][]){}){}){}()){}){}{}[])()()){{}<>{}(<>)}{}((){[](<{}>)}{}){{}<>[({}<[{}]>)](<>)}{}<>(({}()))<>}

在线尝试!

将每个开口存储[在正确的堆栈中,并在我们点击时输出]



5

JavaScript,69 62字节

在火车回家中快速打高尔夫球。可能可以改进。

将输入作为字符数组,并输出一个对象,其键为[s 的索引,其值为相应]s 的索引。

a=>a.map((x,y)=>x==`]`?o[a.pop()]=y:x==`[`&&a.push(y),o={})&&o

在线尝试


令我震惊的是,您可以在手机上打高尔夫球。:P
奥利弗·奥利弗

2
@Oliver,让我惊讶的是,我完全可以(几乎)在触摸屏打字-带回键盘!
粗野的

4

Haskell92 79字节

g(u:a)n(']':x)=(u,n):g a(n+1)x
g a n(s:x)=g([n|s=='[']++a)(n+1)x
g[]_[]=[]
g[]0

在线尝试!

说明

我们创建一个带有g3个参数的函数。

  • a,这是所有不匹配[s 的位置。

  • n,即已处理的字符数

  • x 这是未处理的字符。

如果我们的第一个角色是]我们,u则从最前面移走我们的a并返回,(u,n)再加上剩下的任何东西。

g(u:a)n(']':x)=(u,n):g a(n+1)x

如果我们的第一个字符不是][或者是另一个,我们将增加n并添加[n|s=='[']到的前面a[n|s=='[']将是[n]如果s=='['[]否则。

g a n(s:x)=g([n|s=='[']++a)(n+1)x

如果字符不足,则返回空列表。

g[]_[]=[]

1
哇,多数民众赞成在一些不错的递归函数。我是Haskell的初学者,这让我印象深刻:)
风车饼干

@ gnu-nobody谢谢!这个答案可能不是最佳选择,所以我鼓励您尝试击败它,或者等到认真的Haskell高尔夫球手到来。
小麦巫师

我最好等到严肃的Haskell高尔夫球手到来
风车饼干

4

Java 10,95个字节

将输入字符串作为int[]Unicode代码点的空lambda 。

s->{int r=0,w=0;for(var c:s){if(c==91)s[w++]=r;if(c==93)System.out.println(s[--w]+","+r);r++;}}

在线试用

不打高尔夫球

s -> {
    int r = 0, w = 0;
    for (var c : s) {
        if (c == 91)
            s[w++] = r;
        if (c == 93)
            System.out.println(s[--w] + "," + r);
        r++;
    }
}

致谢

  • 感谢Jonathan Frech提出的使用输入字符串作为堆栈的想法(在这里

您必须定义r并将其w作为代码的一部分,而不是参数:s->{int r=0,w=0;...}
奥利维尔·格雷戈尔(OlivierGrégoire),

@若即若离OlivierGrégoire类,但这个看起来像它的目的是要覆盖多个空输入。
雅各布

1
您引用的答案明确回答了以下问题:“是否允许我们使用空参数,而不是在任何地方都不会使用?”。您正在使用这些输入。我在这里一点都没有歧义。
奥利维尔·格雷戈尔(OlivierGrégoire),

问题的编辑部分使变量“无用”绝对明确。
奥利维尔·格雷戈尔(OlivierGrégoire),

是的,但是为什么最上面的答案(1)没有说明输入未使用,(2)指定额外输入的值是什么,以及(3)提到滥用额外输入的可能性?无论如何,我将移动变量。
雅各布

4

vim,89个字节

:s/\(.\)/\1<C-V><C-M>/g|g/^\[/ :norm %mm%:pu! =line('.').','.line(\"'m\")<C-V><C-M><C-X>$<C-X>J
:v/\[/d|%s/\[//g

带注释

:s/\(.\)/\1<C-V><C-M>/g            " one character per line
|g/^\[/                            " for each opening square bracket:
  :norm %mm%                       "   mark the line with the matching bracket
  :pu! =line('.').','.line(\"'m\") "   write the line numbers to preceeding line
  <C-V><C-M><C-X>$<C-X>J           "   convert to 0-based counting and join lines
:v/\[/d                            " remove all non-opening bracket lines
|%s/\[//g                          " remove brackets

<C-V>是0x16。<C-M>是0x0d。<C-X>是0x18。

在线尝试!


4

QBasic中(QB64),137个 127 112字节

INPUT a$
for i=0to len(a$)
c$=mid$(a$,i+1,1)
if"["=c$then
b(n)=i
n=n+1
elseif"]"=c$then
n=n-1
?b(n),i
endif
next

我们需要四个两个字节,因为挑战需要0索引。我的第一篇QBasic帖子,感谢您的反馈。

  • 10字节归功于steenbergh
  • 3字节归功于Erik the Outgolfer
  • 通过以Unix文件格式(\r\n-> \n)保存12个字节

执行后看起来像这样:

看起来如何


好东西。指针的情侣:使用?替代print(编译器自动扩展这print),您不需要引用的字符串之间的空间THEN中的IFS,你可以删除iNEXT
steenbergh

@steenbergh咦,好像我忘了删除空格...但我删除之间的一个0to?我很困惑……
wastl

1
不确定QB64,但是我认为if c$="["可以变为if"["=c$elseif c$="]"可以变为elseif"]"=c$end if可以变为endif,并且在输出略有变化的情况下也?b(n),i可以变为?b(n)i(我使用QBasic 1.1,您的情况可能有所不同)。
暴民埃里克(Erik the Outgolfer)

@EriktheOutgolfer几乎全部都?b(n)i工作了
wastl

3

Pyth,26个字节

VQIqN\[=+YZ)IqN\],.)YZ)=hZ

在这里尝试

说明

VQIqN\[=+YZ)IqN\],.)YZ)=hZ
VQ                     =hZ   For each character in the input (indexed by Z)...
  IqN\[=+YZ)                 ... if the character is [, add the index to Y...
            IqN\],.)YZ)      ... if the character is ], output the previous index
                             and current index.

真好!我的幼稚方法是36个字节C,x"[" MQ #.e*qb\[t+lhfSI/LT"[]"._>Q。编辑:我成功了高尔夫矿相当有点过了,我现在是低于30
Xcoder先生

3

R141133115112108字节

function(y,x=utf8ToInt(y)){for(i in seq(x)){if(x[i]==91)F=c(i,F);if(x[i]==93){T=c(T,F[1],i);F=F[-1]}};T[-1]}

在线尝试!

没什么特别的。1索引,因为我是这样说的。R不真的有栈,所以我最初使用cheadtail得到同样的文字效果。原始版本(使用utf8ToInt来删除一些字节,使用向量的开始作为堆栈的顶部,并滥用TF内建函数以避免初始化堆栈)。

f <- function(y, x=el(strsplit(y,""))) {
  p <- l <- NULL
  for(i in seq_along(x)) {
    if(x[[i]]=='[') {
      p <- c(p, i)
    }
    if(x[[i]]==']') {
      l <- c(l, tail(p, 1), i)
      p <- head(p, -1)
    }
  }
  l # Because I said so. Change to l-1 if you want to check the test cases.
}


并且1:nchar(y)比短seq_along(x)。顺便说一句非常好的解决方法:)
JayCe

我想知道那gregexpr是不是要走的路。
ngm

我最初尝试使用这种方法,但是我不确定这是否是正确的方法。
JayCe

JayCe解决方案存在缺陷(检查结果,它返回22 28 22而不是返回22 28 21)可能是T / F的(滥用)使用不是真正安全的:D。它更短了,似乎可以用-> 在线试用!
digEmAll

2

第四(gforth),75字节

: f 0 do dup i + c@ dup 91 = if i s>f then 93 = if f>s . i . cr then loop ;

在线尝试!

滥用浮点堆栈,但是允许使用a,do loop因为代码不会(手动)接触返回堆栈。

说明

  1. 遍历字符串中的字符
  2. 检查每个字符
    1. 如果等于[,则放在浮点堆栈上
    2. 如果等于]从浮点堆栈中弹出并以当前位置输出

代码说明

0 do                 \ start a loop from 0 to string-length
  dup                \ duplicate the starting address to avoid losing it
  i + c@             \ get the address of the current position and retrieve the character
  dup                \ duplicate the character, to allow checking twice
  91 = if            \ if char = [
    i s>f            \ store the current address on the floating point stack
  then               \ end the if-statement
  93 = if            \ if char = ]
    f>s .            \ pop the starting position from the float-stack and print
    i .              \ print the current position
    cr               \ output a newline
  then               \ end the if-statement
loop                 \ end the loop

2

视网膜,36字节

L$v`\[((\[)|(?<-2>])|[^]])*
$.`,$.>`

在线尝试!说明:

L

根据比赛结果生成列表。

$

使用以下替换生成列表而不是匹配项。

v`

允许匹配重叠。

\[((\[)|(?<-2>])|[^]])*

这是.NET平衡组的应用。该[字面匹配,然后尽可能多的字符可能被消耗。随着每个后续项[的匹配,该匹配项将添加到$2堆栈中。如果该堆栈不为空,则可以匹配一个],从堆栈中删除匹配项。否则,我们可以匹配所有不匹配的内容][之前已经匹配过)。当满足匹配的匹配停止][,因为$2在该点堆栈是(现在)清空。

$.`,$.>`

替换包含两个用逗号分隔的变量。的.表示该变量的长度,而不是它的值,可以使用。的>表示该变量应在右侧分离器,而不是匹配方面进行评估。的$`变量是指匹配,这意味着的前缀$.`给出的位置[; 的>修改改变了这种对比赛的正确分离,这使匹配位置的前缀]


2

果冻 22 21 20  19 字节

毫无疑问,在Jelly中有可能将这个字节数减半:p ...

n€Ø[ḅ-µMịÄÐƤi€0ĖƊ’Ä

接受字符列表的单子链接,该链接返回整数列表的列表。
作为一个完整的程序,它接受一个字符串并打印所述列表的表示形式。

在线尝试!

怎么样?

n€Ø[ḅ-µMịÄÐƤi€0ĖƊ’Ä - Link: list of characters    e.g. "[f[o]o!]"
  Ø[                - list of characters = ['[', ']']
n€                  - not equal? for €ach              [[0,1],[1,1],[0,1],[1,1],[1,0],[1,1],[1,1],[1,0]]
                    -     ...relating to the characters:  [     f     [     o     ]     o     !     ]
    ḅ-              - convert from base -1             [1,0,1,0,-1,0,0,-1]
                    -     ...i.e.: 1 where '['; -1 where ']'; and 0 elsewhere
      µ             - start a new monadic chain with that as the argument, say V
                Ɗ   - last 3 links as a monad (function of V):
          ÐƤ        -   for post-fixes:
         Ä          -     cumulative sum               [[1,1,2,2,1,1,1,0],[0,1,1,0,0,0,-1],[1,1,0,0,0,-1],[0,-1,-1,-1,-2],[-1,-1,-1,-2],[0,0,-1],[0,-1],-1]
            i€0     -   1st index of 0 in €ach (or 0)  [8,1,3,1,0,1,1,0]
               Ė    -   enumerate                      [[1,8],[2,1],[3,3],[4,1],[5,0],[6,1],[7,1],[8,0]]
       M            - maximal indices of V             [1,3]
        ị           - index into                       [[1,8],[3,3]]
                 ’  - decrement                        [[0,7],[2,2]]
                  Ä - cumulative sum (vectorises)      [[0,7],[2,4]]

我正在尝试使用œ¿,它是亲戚,但是找不到解决方案。是我最接近的。
dylnan

是的,它可以更短一些,但是我只管理了一个字节,而不是一半字节。仍然感觉太久了。:(
Erik the Outgolfer

@EriktheOutgolfer在这里也有一个简单的1字节保存
Jonathan Allan

2

SWI-Prolog 254字节

d([']'|T],I,[S|Z],M,R):-J is I+1,d(T,J,Z,[',','(',S,',',I,')'|M],R).
d(['['|T],I,S,M,R):-J is I+1,d(T,J,[I|S],M,R).
d([_|T],I,S,M,R):-J is I+1,d(T,J,S,M,R).
d(_,_,_,R,R).
m(X):-atom_chars(X,A),d(A,0,[],[']'],[_|R]),atomic_list_concat(['['|R],S),print(S).

例:

?- m('!^45sdfd[hello world[[djfut]%%357]sr[jf]s][srtdg][]').
'[(49,50),(42,48),(8,41),(36,39),(20,33),(21,27)]'
true 

1

C(gcc),87个字节

f(char*Z){for(char*z=Z,*q=z;*z;*z++-93||printf("%d,%d;",*--q,z-1-Z))*z-91||(*q++=z-Z);}

在线尝试!

说明

为了跟踪左方括号的字符串索引,输入字符串将被覆盖并用作堆栈。

f(char*Z){          // take mutable input string
 for(char*z=Z,*q=z; // copy pointer to current string index, current stack index
 *z;                // loop through the entire string
 *z++-93||          // if z == ']'
   printf("%d,%d;", // decrement stack pointer,
    *--q,z-1-Z))    //  write bracket pair position
  *z-91||           // if z == '['
   (*q++=z-Z);}     // write bracket position onto stack, increment stack pointer

在线尝试!


1

果冻,20字节

=©ⱮØ[_/aÄ$+®ŻĠḊẎ_2s2

在线尝试!

它对寄存器有副作用,希望它可以作为一个函数。


它是可重用的,所以我认为很好。高炉答案通常不会使磁带空白
dylnan

1

Japt v1.4.5,23个字节

;Ë¥']?ApENo):D¥'[©NpE
A

在线尝试!

开箱及其工作方式

;UmDE{D==']?ApENo):D=='[&&NpE
A

;                              Use alternative set of initial variables
                               A = [] is used here
 UmDE{                         Map over each char of input string...
      D==']?                     If the char is closing bracket...
            ApENo)                 Push the current index and N.pop() to A
                  :D=='[&&       Otherwise, if the char is opening bracket...
                          NpE      Push the current index to N

A     Output A

输出是的展平数组[closing index, opening index]。如果不需要颠倒的顺序,则w在末尾添加即可完成工作(+1字节)。


1

Common Lisp,95个字节

(lambda(u &aux s)(dotimes(p(length u))(case(elt u p)(#\[(push p s))(#\](print`(,(pop s),p))))))
长版
(defun par (string &aux stack)
  (dotimes (pos (length string))
    (case (char string pos)
      (#\[ (push pos stack))
      (#\] (print (list (pop stack) pos))))))
测验
((lambda(u &aux s)(dotimes(p(length u))(case(elt u p)(#\[(push p s))(#\](print`(,(pop s),p))))))
 "!^45sdfd[hello world[[djfut]%%357]sr[jf]s][srtdg][] ")

印刷品:

(21 27) 
(20 33) 
(36 39) 
(8 41) 
(42 48) 
(49 50)

1

K(ngn / k)38 37字节

{b@0N 2#,/=(|':+\-/a)b:&|/a:"[]"=\:x}

在线尝试!

{ } 带参数的功能 x

"[]"=\:x为的出现两个布尔名单"[""]"

a: 分配给 a

|/ 两个列表中的布尔“或”

& 括号在哪里(在哪个索引处)?

b: 分配给 b

-/一个列表,其中1代表"[",-1代表"]",其他地方为0

+\ 部分和

|': 成对最大值(每个元素与前一个元素最大化,初始元素保持不变)

这表示每个字符的括号深度。我们用b(并置索引)对其进行索引,并且仅获得括号的括号深度。

= “分组依据”-将深度映射到发生深度的字典

,/ 连接字典中的值,而忽略键

0N 2# 重塑为2列矩阵(列表列表)

b@b矩阵每个元素的索引


1

果冻20 18字节

节省了1个字节感谢@ user202729通知我µ€)

ẹⱮØ[µ³ḣċþØ[_/Ụị)Z’

在线尝试!

经过几个小时的努力才可以正常工作...我真的很惊讶它这么短:-)

说明

ẹⱮØ[µ³ḣċþØ[_/Ụị)Z’   Main link. Argument: s (string)  '[a[b]c[]][d]'
  Ø[                 Shortcut for the string "[]".
 Ɱ                   For each char in the "[]":
ẹ                      Find the indices of each occurrence in the input.
                     For our example, this gives the array [[1, 3, 7, 10], [5, 8, 9, 12]].

    µ                Begin a new monadic chain, with said array as its argument.
               )     For each of the two sub-arrays q within the array:
                         [[1, 3, 7, 10], [5, 8, 9, 12]]
     ³ḣ                For each item n in q, take the first n chars of the input.
                         [['[',     '[a[',      '[a[b]c[',   '[a[b]c[]]['],
                          ['[a[b]', '[a[b]c[]', '[a[b]c[]]', '[a[b]c[]][d]']]
        þØ[            For each string s in this, and each char c in "[]":
       ċ                 Count the occurrences of c in s.
                         [[[1, 0],  [2, 0],     [3, 1],      [4, 3]],
                          [[2, 1],  [3, 2],     [3, 3],      [4, 4]]]
           _/          Reduce each pair by subtraction. This is the number of open brackets
                         at each position.
                         [[1, 2, 2, 1], [1, 1, 0, 0]]
             U         Sort the indices by their values, using position as a tiebreaker.
                         [[1, 4, 2, 3], [3, 4, 1, 2]]
              ị        Index these values back into q.
                         [[1, 10, 3, 7], [9, 12, 5, 8]]

               )     Start a new monadic chain with the result as its argument.
                Z    Zip; transpose rows and columns.
                         [[1, 9], [10, 12], [3, 5], [7, 8]]
                 ’   Decrement; switch to 0-indexing.
                         [[0, 8], [9, 11], [2, 4], [6, 7]]

1

CJam,25个字节

0q{"[]"#"_ \p_p "S/=~)}/;

出人意料的竞争力-仅输给Japt和Jelly [ 编辑:以及木炭和Stax :(]

在线尝试!

说明

0                          Push 0.
 q                         Push the input.
  {                   }/   For each character in the input:
   "[]"#                     Find index of this character in the string "[]" (or -1 if not found).
                   =         Use this index to choose
        "       "S/            one of the following snippets
                    ~          and execute it:
         _                       If it was 0 ('['), duplicate the number on the stack.
           \p_p                  If it was 1 (']'), print the current number and the one under it.
                                 If it was -1, do nothing.
                     )       Increment the number on top of the stack.
                        ;  Delete the number.


0

Pyth 28  26字节

{I#.e,t+lhfSI/LT`Y+._>Qk\]

测试套件。

目前它比Mnemonic的方法更长,但我觉得我可以稍微降低一点,幸运的是,它也没有使用像Python这样的命令结构V。最初的版本为36字节,还存在许多错误。

怎么运行的

{I#.e,t + lhfSI / LT`Y + ._> Qk \] –完整程序。从STDIN中获取带引号的字符串Q。
   .e –枚举地图。k =迭代索引,b =当前元素。
                     > Qk –以大于k的索引获取Q的元素。
                   ._ –生成所有前缀。
                  + \] –并附加一个“]”(用于处理某些边缘情况)。
          f –过滤此列表,其中T =当前元素。
              L`Y –对于str([])中的每个字符,“ []” ...
             / T – ...计算T中的出现次数。
           SI –并检查这些值是否在递增排序。
         h –头。检索第一个元素。
       + l –获得+ k的长度。
      t –减量(减1)。
     ,–并将该值与k配对。返回[i,k],其中i是
                             对应的]和k的索引是[。
  #–通过以下方式过滤此列表:
{I –重复数据删除对保持不变。

{I#.e,t+lhfSI/LT`Y._>Q 几乎可以工作22个字节...
Xcoder先生,18年

0

Perl 5,53个字节

say"$-[0] ".($+[0]-1)while s/\[[^][]*\]/1x length$&/e

运行为perl -nE '<above code snippet>'。通过stdin输入。

通常,针对该问题的最佳Perl解决方案是一个正则表达式。我们尝试使用一个看起来很傻的字符类(s/\[[^][]*\]/.../)来匹配其中不包含任何对的任何括号。如果匹配成功,我们将匹配的文本1一遍又一遍地替换为数字,这样就不会再意外匹配那些括号,并打印出匹配的索引。冲洗并重复。


0

Stax,13 个字节

é√p(l▓1½\á²ë(

运行并调试

它使用输入堆栈来跟踪大括号对。这是解压,解压和注释的程序。

F       iterate over input characters
 .][I   get the index of the character in the string "[]", or -1
 ^|cv   skip the rest of this iteration if index was -1
 i~     push the current iteration index to the input stack
 C      skip the rest of this iteration if index was 0
 \      form a pair with the top two items from the input stack
 JP     join with space, and print

运行这个


0

木炭,20字节

FLθ≡§θι[⊞υι]«I⊟υ,Iι⸿

在线尝试!链接是详细版本的代码。说明:

FLθ

循环输入字符串长度的隐式范围。

≡§θι

打开当前字符。

[⊞υι

如果是a,[则将当前索引推送到预定义的数组变量。

]«I⊟υ,Iι⸿

如果是a,]则从数组变量中弹出最新索引,然后将其打印并以逗号分隔当前索引并开始新行。替代的输出格式(如果可以接受的话)将节省一些字节:]I⟦⊟υιω节省2个字节,但将每个索引打印在单独的行上,索引对的间距为双倍;]I⟦⊟υι只需将索引打印在单独的行上,就很难区分它们。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.