如何更好地理解“最长有效括号”问题的解决方案?

时间:2019-10-22 23:23:48

标签: python python-3.x algorithm

问题是:

  

给出一个仅包含字符'('和')'的字符串,找到最长的有效(格式正确)括号子字符串的长度

一些例子是:

  

输入:“(()”,输出:2

     

输入:“)()())”,输出4

我在下面找到了这个可行的Python解决方案:

def solution(s):
    if not s or len(s) == 1:
        return 0

    stack = [-1]
    a = 0
    for i,c in enumerate(s):
        if c == '(':
            stack.append(i)
        else:
            stack.pop()
            if stack:
                a = max(a, i - stack[-1])
            else:
                stack.append(i) 
    return a

我无法理解此解决方案为何有效。我已经逐步处理了一些示例输入,但是我看不出它为什么起作用。

如果我理解正确,那么每次遇到左括号时,堆栈都会简单地添加索引。否则,将弹出堆栈,并采用当前索引和最后一个左括号之间的差值。

我的问题是,为什么先弹出堆栈然后再测量长度?为什么我们从第二个括号到最后一个括号进行测量?如果堆栈为空,我也无法理解为什么会有stack.append(i):我不明白这里的逻辑。

1 个答案:

答案 0 :(得分:0)

堆栈包含不平衡字符的索引,始终按升序排列。堆栈的顶部(即stack列表中的最后一个值)是当前不平衡的最右边字符(或-1的特殊索引,指的是“开始”之前的位置)。字符串(如果当前没有任何不平衡字符)。

堆栈的底部是最右边的不平衡)字符的索引,如果到目前为止还没有发现不平衡的-1,则为)。堆栈中的所有其他值将始终是迄今为止不平衡的(字符的索引。随着我们继续遍历字符串,我们稍后可能会平衡它们。

当我们在输入字符串上的迭代中遇到一个新字符时,我们可能会采取三种可能的操作。

  1. 如果新字符是(,我们知道它是不平衡的(目前,因为它是我们处理的最后一个字符),所以我们总是将其压入堆栈顶部。

在其他两种情况下,新字符为)。对于这两者,我们都希望从堆栈顶部弹出一个值,因为前一个值不再是最右边的不平衡字符。

  1. 如果在我们弹出值之后堆栈不为空,则弹出的索引表示不平衡的(字符,而当前的)刚刚使它平衡。

    在这种情况下,我们当前的字符是平衡子字符串的一部分,因此我们检查它是否是迄今为止我们所见过的最长的子字符串。堆栈中的最后一个值是最右边的不平衡字符的索引,而我们的平衡子字符串就从其右边开始。因此,当前子字符串的长度为i - stack[-1],并且如果max调用大于{{1},它将用新长度替换a(以前看到的最长子字符串的长度)。 }}的旧值。

  2. 如果在我们弹出一个值后堆栈为空,那么我们弹出的值就是堆栈的底部。正如我在上面提到的,最低值是不平衡的a字符(或)代表字符串的开头)的索引。如果我们弹出它,则意味着我们当前的-1不平衡!在这种情况下,我们用自己的索引替换弹出的值。这是堆栈的新底部,是最右边的新不平衡)的索引。