32. 最长有效括号
给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
示例 2:
输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"
这是道困难题,看到了括号,我第一想到的就是栈,因为对于匹配括号的题,栈这种数据结构是非常好用的。其次最长有效,这几个字在动态规划题目中经常遇见,所以不妨两者都可以考虑对应解法
动态规划
我们假设DP数组表示以当前字符作为结尾,其能匹配的括号长度
举个例子
index: 0 1 2 3 4 5
括号: ( ( ( ( ) )
DP数组:0 2 0 0 2 4
我们假设当前DP[i] 是i = 4的情况,那么如何推断出DP[i+1]?
首先我们可以知道括号匹配时,其结尾一定是右括号,此时我们条件判断时当结尾为右括号才判断
其次,如果前面已经有匹配的括号,我们自然要跳过
比如index=5前面有了index=4匹配的括号,我们需要加上前面这个匹配的,即加上dp[-1],而另外一点,与index=5匹配的括号肯定不在index=4匹配括号的范围内,因此我们需要跳过,即跳过i - dp[i-1] - 1
此时如果s[i-dp[i-1]-1] 为左括号时,则匹配成功,加2
最后我们还要考虑s[i-dp[i-1]-1]前面是否有匹配,即加dp[i-dp[i-1]-2]
最后状态转移公式为:dp[i] = dp[i-1] + dp[i-dp[i-1]-2] + 2
这些情况可能会导致数组越界,因此我们还需要额外判断使得索引在数组范围内
下面是python代码
class Solution:
def longestValidParentheses(self, s: str) -> int:
"""
动态规划
初始化一个全0的dp数组
代表以改字符结尾的括号长度
:param s:
:return:
"""
n = len(s)
if n == 0:
return 0
dp = [0]*n
for i in range(len(s)):
if s[i] == ')' and i - dp[i-1] - 1>=0 and s[i-dp[i-1]-1] == '(':
dp[i] = dp[i-1] + dp[i-dp[i-1]-2] + 2
return max(dp)
栈
index: 0 1 2 3 4 5 6
括号: ( ) ) ( ( ) )
我们先往栈里放入-1
栈:-1
我们是将数组的索引入栈,当是左括号的时候,就将索引入栈,如果是右括号,则出栈,将当前索引与栈顶元素相减,得到length
并且维护一个最大长度max_length
一开始index=0是左括号,入栈
栈 :-1 0
然后index = 1是右括号,出栈,此时栈里只剩-1,而1 - (-1) = 2,记为length
栈:-1
index = 2是右括号,相对于分割了子串,将-1出栈,此时栈里面没有元素,将 2 入栈
栈:2
index = 3, 4都是左括号,入栈
栈:2 3 4
index = 5 是右括号,将4出栈,此时 5 - 3 = 2
栈: 2 3
类似推导得出最后为4
下面是代码
def longestValidParentheses2(self, s: str) -> int:
"""
使用栈
:param s:
:return:
"""
stack = [-1]
length = 0
max_length = 0
for i in range(len(s)):
if s[i] == '(':
stack.append(i)
else:
stack.pop()
if stack == []:
stack.append(i)
else:
length = i - stack[-1]
max_length = max(max_length, length)
return max_length