32-Longest-Valid-Parentheses
Last updated
Was this helpful?
Last updated
Was this helpful?
给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。
注意注意:这道题要求的是连续最长子括号的长度,一定得是连续的。求一个字符串中括号能否匹配用栈是很简单的。关键是怎么保证连续这个状态。
我刚开始是直接栈中保存左括号或者右括号了,一旦括号匹配,就将结果加2。这种做法只能求出字符串中有效括号的数量。而不是连续的括号数量。所以转而在栈中保存括号对应的下标。基本规则如下:
首先要在栈中添加-1
,这是为了解决()
这种情况。第一组括号就直接匹配,长度为右括号下标减去栈顶中的下标。也就是1-(-1)=2
如果当前字符为(
,那么直接push对应的下标
如果当前字符为)
,首先pop栈顶元素,
如果栈顶为空,那么push当前下标
否则更新结果:result=Math.max(result,i-stack.peekLast()
。因为i是当前右括号的下标,如果弹出的是左括号,那么新栈顶就是左括号下标j的左边一个j-1
,二者相减才是这组括号的长度。
从上面的规则可以看出,栈中要么保存一个)
或者不保存。对于测试用例为))))
,刚开始栈顶元素为-1
,遇到第一个)
,弹出栈顶,计算的结果为0。然后栈为空,会将第二个)
下标push到栈中。往后都只会保存一个(
直到遍历结束。
对于最优的策略,一定有最后一个元素 s[i]
所以,我们先看第i个位置,这个位置的元素s[i]可能有如下两种情况:
s[i] == '(' 这时,s[i]无法和其之前的元素组成有效的括号对,所以,dp[i] = 0
s[i] == ')' 这时,需要看其前面对元素来判断是否有有效括号对。
情况1: s[i - 1] == (
即s[i]和 s[i - 1]组成一对有效括号,有效括号长度新增长度2,i位置对最长有效括号长度为 其之前2个位置的最长括号长度加上当前位置新增的2,我们无需知道i-2位置对字符是否可以组成有效括号对。
那么有:dp[i]=dp[i−2]+2
情况2: s[i - 1] == )
这种情况下,如果前面有和s[i]组成有效括号对的字符,即形如((....))
,这样的话,就要求s[i-1]位置必然是有效的括号对,否则s[i]无法和前面对字符组成有效括号对。</br> 这时,我们只需要找到和s[i]配对位置,并判断其是否(
即可。其配对位置为:i−dp[i−1]−1(i-dp[i-1]是s[i-1]的配对位置,再减1就是s[i]的配对位置)。
如果:s[i-dp[i-1]-1] == (
,那么有效括号长度新增长度2,i位置对最长有效括号长度为i-1位置的最长括号长度加上当前位置新增的2,那么有:dp[i]=dp[i−1]+2
值得注意的是,i−dp[i−1]−1 和 i组成了有效括号对,这将是一段独立的有效括号序列,如果之前的子序列是形如 (...)这种序列,那么当前位置的最长有效括号长度还需要加上这一段。所以: dp[i]=dp[i−1] + dp[i−dp[i−1]−2]+2
注: 这个在分析时是很容易遗漏的,分析要更细致。我在第一次分析是就遗漏了,提交后,有用例 )()(()))不过,分析后发现是少了这一段。
栈版本:
动态规划版本:
对于测试用例有连续索引的题目,如果题目要求最后的结果是连续的长度,并且可能会用到栈或队列来求。那么在栈中一般都是保存元素对应的索引,而不是真正的元素,因为这样不仅能求出长度,还能保证结果是连续的。
由于这道题我实在想不出来递归函数该怎么写,导致最后dp版本也无从下手。下面解析摘抄自: