Python 如何在字符串中找到最大的有效圆括号和方括号序列?

Python 如何在字符串中找到最大的有效圆括号和方括号序列?,python,algorithm,stack,dynamic-programming,parentheses,Python,Algorithm,Stack,Dynamic Programming,Parentheses,因此,我需要编写一个脚本,最大的问题之一可以归结为在字符串中找到最大的有效子序列。所以我有点像 "()(({}[](][{[()]}]{})))(" 作为输入,我需要返回 "[{[()]}]{}" 作为输出 我曾经尝试过使用类似堆栈的结构,如果它只是圆括号的话,你会这样做,但我一直无法找到一些有效的方法。我更喜欢python的解决方案,但任何人提供的任何指导都会有所帮助,无论使用何种语言。理想情况下,效率应该比n^2好,因为我可以想到一个O(n^2)解决方案,使用它并在不同的子串上尝试它

因此,我需要编写一个脚本,最大的问题之一可以归结为在字符串中找到最大的有效子序列。所以我有点像

"()(({}[](][{[()]}]{})))(" 
作为输入,我需要返回

"[{[()]}]{}" 
作为输出


我曾经尝试过使用类似堆栈的结构,如果它只是圆括号的话,你会这样做,但我一直无法找到一些有效的方法。我更喜欢python的解决方案,但任何人提供的任何指导都会有所帮助,无论使用何种语言。理想情况下,效率应该比n^2好,因为我可以想到一个O(n^2)解决方案,使用它并在不同的子串上尝试它

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

似乎您正在寻找:

  • 字方括号
  • 一堆不是末端括号的字符
  • 闭式括号
  • 开口撑杆
  • 所有字符直到最后一个闭合括号
  • 闭合支架
语言不可知论,比如:

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

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

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

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

()(({}[]([{[()]}]{})))(
11  2233    44   55
第二步是将种子扩展成序列。序列是一组嵌套的符号:例如
[{[()]}]
。因此,从种子开始,向外工作,验证封闭符号是否匹配。搜索在不匹配处结束,或在字符串的开头或结尾结束。在本例中,只有种子4由匹配符号封闭,因此仅扩展种子4

()(({}[]([{[()]}]{})))(
11  2233 4444444455
()(({}[]([{[()]}]{})))(
11  2222444444444444
步骤3是组合相邻序列。请注意,可以有两个或多个相邻序列,但在示例中,两个位置有两个相邻序列

()(({}[]([{[()]}]{})))(
11  2222 4444444444
重复步骤2,将组合序列视为种子。在本例中,序列4由匹配的括号括起,因此序列4展开

()(({}[]([{[()]}]{})))(
11  2233 4444444455
()(({}[]([{[()]}]{})))(
11  2222444444444444
重复步骤3,合并序列

()(({}[]([{[()]}]{})))(
11  2222222222222222
重复步骤2,展开

()(({}[]([{[()]}]{})))(
1122222222222222222222
再结合一次

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


实施说明:

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

扩展序列包括检查
数组[start-1]
数组[end+1]
处的符号,然后根据需要更新
开始
/
结束
索引

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


一旦一个序列被尽可能多地展开/合并,移动到列表中的下一个序列。当这个新序列被展开/合并时,它可能最终返回到上一个序列。因此,在最初创建种子的双链接列表后,通过链接列表一次就足以展开/合并所有序列影响。然后需要第二次遍历链表的剩余部分以找到最长的序列。

这可以使用动态规划来解决。遍历记录每个索引结束的最长有效匹配的数组。如果索引i的匹配最长,则很容易找到索引i+1的最长匹配:跳过b确认索引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("{}[()()()()()()()]")
def最长\u有效:
匹配=[0]*(长度+1)
对于x范围内的i(1,len(s)):
如果s[i]在“({[”):
持续
open='({['[']}]'.索引(s[i])]
开始=i-1-匹配[i-1]
如果开始<0:继续
如果s[start]!=打开:继续
匹配[i]=i-start+1+匹配[start-1]
最佳=最大(匹配)
结束=匹配索引(最佳)
返回s[结束+1-最佳:结束+1]
打印最长有效(“()({}[]([{{[()]}]{}]))(”)
打印最长有效(“()({}[]([{[()]}]{}]))()
打印最长的U有效(“{}[()]”)

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

这是一个老问题,但我想我会提出一种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("{[([](){}})]")             # [](){}

在我看来,正确的答案应该是除了最后一个
,或者我对这个问题有误解吗?不,你没有。我只是很愚蠢。实际上,我喜欢输入序列,我只是想确保我们同意输出序列:)“有效”这里的意思是,一个左括号后面总是跟着它匹配的右括号,并且此时没有打开的内括号对?因为您没有说明“valid”是什么。这比O(n^2)好吗?看起来应该是O(n)在每一个扩展/合并步骤中,由于我看不到一个很好的方法来完成merging@user1984974我想很快就会好的