一、题目
给定一个只包含 '('
和 ')'
的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
示例 2:
输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"
二、思路
1. 栈
创建一个空栈stack
,同时创建一个标志数组flag
,数组长度等于字符串s
长度,初始值全部为0(0代表非有效括号,1代表有效括号一部分)。
对字符串s
进行遍历,当遍历到的字符是(
,则将其下标添加到栈stack
中。如果是)
,并且栈不为空,则将栈顶下标抛出,同时将栈顶下标与当前遍历的下标在flag
中的对应位置的值改为1
。
当字符串s
遍历结束,然后对标志数组flag
进行遍历。统计数组中连续为1
的长度,然后与max_length
(有效括号最大长度)对比,将比较大的值赋值给max_length
。
最后返回max_length
。
2. 动态规划
我们首先定义一个数组dp
,用来统计最长有效括号的长度,数组长度与字符串s
的长度相等,并且将值全部初始化为0。用dp[i]
表示以下标为i
的元素为结尾的最长有效括号的长度。
我们还知道有效括号必须以)
结尾,所以我们只需要计算)
在dp
数组中对应位置上的值即可。
我们从前往后遍历字符串s
,遇到)
边进行统计,由于要形成有效括号,字符串s
长度至少为2,所以代码中直接从第二个元素也就是下标为1
的位置开始遍历:
如果s[i] == ")"
:
情况一:如果
s[i-1] == "("
,这时s[i]
与s[i-1]
正好是一对有效括号,所以
$$
dp[i] == dp[i-2] + 2
$$如果
s[i-1] == ")"
,这时我们就需要判断s[i - dp[i-1] - 1] == "("
,如果成立,那么
$$
dp[i] = dp[i-1] + dp[i - dp[i-1] - 2] + 2
$$
到此为止,已经得到状态转移方程,接下来需要进行一些条件限定:
- 在第一种情况中,需要确保
i-2 >= 0
- 在第二种情况中,要保证
i - dp[i-1] - 1 >= 0
最后返回数组dp
中的最大值。
三、代码
1. 栈
class Solution:
def longestValidParentheses(self, s: str) -> int:
# 栈
stack = []
# 标志数组,保存有效括号的位置
flag = [0 for _ in range(len(s))]
# 有效括号的最大长度
max_length = 0
# 当前有效括号的长度
cur = 0
for i in range(len(s)):
if s[i] == '(':
stack.append(i)
elif s[i] == ')' and stack:
index = stack.pop()
flag[i], flag[index] = 1, 1
for k in range(len(flag)):
if flag[k]:
cur += 1
# 保证当前元素不是最后一个
if k + 1 < len(flag):
# 下一个标志位置为0,则进行长度比较、更新
if not flag[k+1]:
max_length = max(cur, max_length)
else:
max_length = max(cur, max_length)
else:
cur = 0
return max_length
2. 动态规划
class Solution:
def longestValidParentheses(self, s: str) -> int:
n = len(s)
# 创建一个dp数组
dp = [0 for _ in range(n)]
for i in range(1, n):
if s[i] == ')':
if s[i-1] == '(':
dp[i] = (dp[i-2] if i-2>=0 else 0) + 2
elif s[i-1] == ')':
if 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 if dp else [0])
四、表现
method | 运行时间 | 表现 | 内存消耗 | 表现 |
---|---|---|---|---|
1. 栈 | 56ms | 71.14% | 14.1MB | 5.02% |
2. 动态规划 | 56ms | 71.36% | 13.9MB | 41.84% |