【问题标题】:How do I find largest valid sequence of parentheses and brackets in a string?如何在字符串中找到最大的有效括号和括号序列?
【发布时间】:2016-12-14 22:03:28
【问题描述】:

所以我有一个需要编写的脚本,而最大的问题之一归结为在字符串中找到最大的有效子序列。所以我有类似的东西

"()(({}[](][{[()]}]{})))(" 

作为输入,我需要返回

"[{[()]}]{}" 

作为输出。

我尝试过使用类似堆栈的结构,如果它只是括号,但无法找出可行的方法。我更喜欢 python 中的解决方案,但任何人可以提供的任何指导都会有所帮助,无论语言如何。理想情况下,效率应该比 n^2 更好,因为我可以想到使用此 How to find validity of a string of parentheses, curly brackets and square brackets? 的 O(n^2) 解决方案,并在不同的子字符串上尝试它

【问题讨论】:

  • 在我看来,正确的答案应该是除了最后一个(之外的所有内容,还是我对这个问题有误解?
  • 不,你不是。我只是愚蠢。已编辑
  • 实际上,我喜欢输入序列,我只是想确保我们在输出序列上达成一致:)
  • “有效”这里的意思是左括号后面总是跟着它匹配的右括号,此时没有打开的内括号对?因为你没有说明什么是“有效”。

标签: python algorithm stack dynamic-programming parentheses


【解决方案1】:

这可以使用动态规划来解决。遍历记录从每个索引结束的最长有效匹配的数组。如果你有索引 i 的最长匹配,那么很容易找到索引 i+1 的最长匹配:向后跳过索引 i 的最长匹配,然后查看周围的字符是否匹配开/关括号。然后将最长的匹配也添加到它的左侧,如果有的话。

这里有一些计算这个的 Python 代码:

def longest_valid(s):
    match = [0] * (len(s) + 1)
    for i in xrange(1, len(s)):
        if s[i] in '({[':
            continue
        open = '({['[')}]'.index(s[i])]
        start = i - 1 - match[i - 1]
        if start < 0: continue
        if s[start] != open: continue
        match[i] = i - start + 1 + match[start - 1]
    best = max(match)
    end = match.index(best)
    return s[end + 1 - best:end + 1]

print longest_valid("()(({}[](][{[()]}]{})))(")
print longest_valid("()(({}[]([{[()]}]{})))(")
print longest_valid("{}[()()()()()()()]")

在时间和空间上是 O(n)。

【讨论】:

  • 我认为下面的“[[(])]”应该返回“[[]]”,但是上面的代码返回“”
【解决方案2】:

此答案使用以下输入序列作为示例。预期的输出是除最后一个 ( 之外的所有字符串。

Input:  ()(({}[]([{[()]}]{})))(
Output: ()(({}[]([{[()]}]{})))

第一步是在字符串中找到种子。种子是一组匹配的符号:()[]{}。我给每个种子一个数值,以帮助读者将种子可视化。

()(({}[]([{[()]}]{})))(
11  2233    44   55

第 2 步是将种子展开为序列。序列是一组嵌套的符号:例如[{[()]}]。因此,从种子开始,向外工作,验证封闭符号是否匹配。搜索在不匹配处结束,或者在字符串的开头或结尾处结束。在示例中,只有种子 4 被匹配符号包围,因此只有种子 4 被扩展。

()(({}[]([{[()]}]{})))(
11  2233 4444444455

第三步是合并相邻的序列。注意可以有两个或多个相邻的序列,但是在例子中两个地方有两个相邻的序列

()(({}[]([{[()]}]{})))(
11  2222 4444444444

重复第 2 步,将组合序列视为种子。在本例中,序列 4 用匹配的括号括起来,因此扩展了序列 4。

()(({}[]([{[()]}]{})))(
11  2222444444444444

重复第 3 步,组合序列

()(({}[]([{[()]}]{})))(
11  2222222222222222

重复第 2 步,展开

()(({}[]([{[()]}]{})))(
1122222222222222222222

再组合一次

()(({}[]([{[()]}]{})))(
1111111111111111111111

当没有任何东西可以扩展或组合时,算法结束。最长的序列就是答案。


实施说明:

我认为您可以通过一次扩展/合并一个序列来实现O(n)。我会将序列列表保存在双向链表中(因此删除是O(1) 操作)。每个序列将由一个start 索引和一个end 索引表示。

扩展序列涉及检查array[start-1]array[end+1] 处的符号,然后根据需要更新start/end 索引。

合并涉及检查链表中的下一个和上一个序列。如果可以合并序列,则更新一个序列以覆盖整个范围,并删除另一个序列。

一旦一个序列被尽可能地扩展/合并,移动到列表中的下一个序列。随着这个新序列被扩展/合并,它最终可能会回到之前的序列。因此,在最初创建种子的双向链表之后,通过链表应该足以扩展/合并所有序列。然后需要再次遍历链表的任何剩余部分以找到最长的序列。

【讨论】:

  • 这是否比 O(n^2) 更好?似乎在每个展开/合并步骤中充其量是 O(n),因为我看不到进行合并的好方法
  • @user1984974 我认为它会在 O(n) 时间内工作。我在答案的末尾添加了一些注释来解释。
【解决方案3】:

如果您谈论的是任意深度,此处的 Franks anser 可能适用: Regular expression to detect semi-colon terminated C++ for & while loops

如果我们谈论的是有限深度,Regex 可能是您的朋友(您可能想检查性能)

您似乎在寻找:

  • 文字方括号
  • 一堆不是结束括号的字符
  • 右括号
  • 打开大括号
  • 直到最后一个大括号的所有字符
  • 右大括号

所以,与语言无关的东西,例如:

\[[^]]*\{.*\}

这可以与 Python 的 re.compile 一起使用,但实际上它可以是任何语言。由于假定 .*(任何字符)和 [^]](非结束方括号),您可以使用 w+ 或 d+ 表示单词/数字或其他正则表达式简写来改进解决方案并加快速度。

【讨论】:

    【解决方案4】:

    这是一个老问题,但我会贡献一个 O(n) 方法,它会单次遍历字符并使用堆栈跟踪匹配项。当找到连续的平衡组时,它会将长度汇总到前一个嵌入组。

    from collections import deque
    def balanced(s):
        groups = {"(":")", "[":"]", "{":"}"}
        result = ""
        starts = deque([["",0,0]])              # stack of [closingChar,position,width]
        for i,c in enumerate(s):
            if c in groups:
                starts.append([groups[c],i,1])  # stack opening groups
            elif c != starts[-1][0]:
                starts = [["",i+1,0]]           # unmatched open/close, clear stack
            else:
                _,p,w   = starts.pop()                     # close group
                if not starts: starts.append(["",p,0])     # maintain ungrouped baseline
                starts[-1][2] = w = starts[-1][2] + w + 1  # roll up group size
                if w-w%2>len(result):                      # track longest
                    result = s[starts[-1][1]+w%2:][:w-w%2] # w%2 handles grouped/ungrouped
        return result
    

    输出:

    balanced("()(({}[](][{[()]}]{})))(") # [{[()]}]{}
    
    balanced("()(({}[]([{[()]}]{})))(")  # ()(({}[]([{[()]}]{})))
    
    balanced("{}[()()()()()()()]")       # {}[()()()()()()()]
    
    balanced("{[([](){}})]")             # [](){}
    

    【讨论】:

      猜你喜欢
      • 2011-01-31
      • 1970-01-01
      • 2014-11-15
      • 2013-02-15
      • 1970-01-01
      • 1970-01-01
      • 2018-04-14
      • 2022-11-18
      • 1970-01-01
      相关资源
      最近更新 更多