题目描述
给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
示例 2:
输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"
解题思路一
利用堆栈的特点:先进后出,匹配左括号和右括号进行有效括号的查找,更新孤立的左括号或者右括号在输入字符串中的索引,计算最长有效括号子串长度。
1、考虑一种特殊情况,输入字符串为空字符串,最长有效括号字串长度是0。
if not s:
return 0
2、用list模拟堆栈时,应该赋初值。
如果输入的字符串是以”)“开头的,根据匹配规则,左括号”(“入堆,右括号出堆栈”)“,list初始是空会报错。
stack = [-1]
为什么初始值设置为-1,这个跟下面计算最长有效括号字串长度有关。
3、计算最长字串
遍历整个输入字符串,遇到左括号,索引入堆栈stack,判断下一个字符是否是右括号,如果是,则左括号的索引出堆栈否则保留。
如果遍历过程中,stack为空,则添加索引 i到stack中,初始值被弹出,说明i是不能被匹配的孤立右括号。
如果遍历结束后,stack非空,记录的是最后不能被匹配的左括号索引,此时最长有效括号字串长度等于之前有记录的最长字串长度与后续计算得到的字串长度二者之中的最大值。
res = max(res,i-stack[-1])
完整python代码:
class Solution:
def longestValidParentheses(self, s: str) -> int:
if not s:
return 0
stack = [-1]
res = 0
for i in range(len(s)):
if s[i] == '(':
stack.append(i)
else:
stack.pop()
if not stack:
stack.append(i)
else:
res = max(res,i-stack[-1])
return res
解题思路二
动态规划。动态规划其实就是逐一累加,当前的结果依赖之前的结果,逐步从前向后推理,得到最终的结果。
基本算法过程:
1、显然,s 是空字符串时,返回0
2、建一个list用于存储从左到右每一步的结果,list长度就是字符串s的长度,每一个位置代表到这个位置时累计到的最长字串
3、找出list中的最大值,也即是最长字串
考虑几种情况:
(1)s[i] = '(' 时,list[i] = 0
(2)s[i] = ')', s[i-1] = '(' 则有 list[i] = list[i-2] + 2
解释一下:
当第i位和第i-1位是成对的括号时,此时到i位置括号字串的长度就等于第i-2位对应的括号字串长度加上2(一
对括号的长度是2)
换句话说,当前找到了一对相邻的'()',那么到当前位置i的字串长度就等与i-2位置处的字串长度
加上当前字串长度2
举个例子:s = '((()'
list = [0] * len(s)
s[0] = '('===> list[0] = 0
s[1] = '(' ===> list[1] = 0
s[2] = '(' ===> list[2] = 0
### 划重点
s[3] = ')' ===> list[3-1] = '('
list[3] = list[3-2] + 2 = 2
(3) s[i] = ')', s[i-1] = ')', i-list[i-1]-1 >=0 & s[i-dp[i-1]-1] == '(' 则有:list[i] = list[i-1] + list[i-list[i-1]-2] + 2
解释一下:
当出现两个连续的')'时,由于是从左向右匹配的,所以假设第一个')'已经找到了匹配项,
那么接下来只需要匹配第二个')'对应的'('即可,此时要跳过第一个')'的匹配项,即判断
s[i-list[i-1]-1] == '(' 同时为了防止索引溢出判断 i-list[i-1]-1 >=0
如果以上限制都满足,则有:
list[i] = list[i-1] + list[i-list[i-1]-1-1] + 2
当前i位置的字串长度就等于i-1处位置上的字串长度加上i-list[i-1]-1-1位置上的字串长度
加上字串本身长度2
举个例子:s = '((())'
list = [0] * len(s)
s[0] = '('===> list[0] = 0
s[1] = '(' ===> list[1] = 0
s[2] = '(' ===> list[2] = 0
### 划重点
s[3] = ')' ===> list[3-1] = '('
list[3] = list[3-2] + 2 = 2
s[4] = ')' & s[4-1] = ')' & 4-list[4-1] - 1 = 1 > 0 & s[4-list[4-1] - 1] == '('
list[4] = list[4-1] + list[4-list[4-1]-2] + 2 = 4
举个复杂点的例子:s = '(()(())'
list = [0] * len(s)
s[0] = '('===> list[0] = 0
s[1] = '(' ===> list[1] = 0
s[2] = ')' ===> list[2] = list[2-2] + 2 = 2
s[3] = '(' ===> list[3] = 0
s[4] = '(' ===> list[4] = 0
s[5] = ')' & s[4] = '(' ===> list[5] = list[5-2] + 2 = 2
s[6] = ')' & s[5] = ')' & 6 - list[6-1] - 1 = 3 > 0 & s[3] == '(' ===>
list[6] = list[6-1] + list[6-list[6-1]-1-1] + 2 = list[5] + list[2] + 2 = 6
( | ( | ) | ( | ( | ) | ) |
---|---|---|---|---|---|---|
0 | 0 | 2 | 0 | 0 | 2 | 6 |
代码:
class Solution:
def longestValidParentheses(self, s: str) -> int:
if not s:
return 0
n = len(s)
dp = [0]*n
for i in range(1,n):
if s[i] == ')':
if s[i-1] == '(':
dp[i] = dp[i-2] + 2
elif s[i-1] == ')' 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)
题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-valid-parentheses