题目
给出一个长度为 n 的,仅包含 ‘(’ 和 ‘)’ 的字符串,计算最长的格式正确的括号子串的长度
动态规划
使用一个长度与字符串相等的dp数组,初始化为全0,每个元素表示:以字符串中当前位置结尾的正确括号子串长度,则有:
-
合法的括号子串一定以
)
结尾,但以)
结尾的不一定合法 -
如果当前位置
i
处的字符为(
,一定不合法,dp[i]
=0 -
若当前位置
i
处的字符为)
,检查它前一个字符
,则有2种情况:
1)形如()
,则此处dp值为dp[i-2]+2
2)形如))
,则对i处的)
即第二个)
来说,它的前面可能有合法的括号子串,长度为dp[i-1]
:
①若该合法的括号子串前面无(
,则此处的)
为多余的右括号,此处dp值为0
②若该合法的括号子串前面恰好有一个(
,则可以形成(...)
的形式,该段(...)
长度为dp[i-1]+2
;考虑到前面这个左括号前还可能有合法的括号子串,所以i处的dp值还需要再加上dp[i - dp[i - 1] - 2]
得到该情况下的状态转移方程为:
dst[i] = dst[i] + dst[i - 1] + 2 + dst[i - dst[i - 1] - 2]
注意防止坐标越界:检查前面的合法子串前是否有(时,要检查i - dst[i - 1] - 1是否>=0;在检查(…)前面是否还有合法子串时,要检查i - dst[i - 1] - 2 是否>= 0
代码
class Solution:
def longestValidParentheses(self, s):
if not s:
return 0
dst = [0] * len(s) # dst中元素表示以当前下标结尾的最长的括号子串长度
# 合法的括号子串一定以)结尾,长度为偶数
# 每次检查当前字符和前一个字符
for i in range(1, len(s)):
# (结尾,一定不是合法括号子串,dp值为0
if s[i] == '(':
continue
# 形如(),则dp值为2格前的dp值+2
elif s[i - 1] == '(' and s[i] == ')':
if i == 1:
dst[i] += 2
else:
dst[i] = dst[i - 2] + 2
# 形如)),则跳过中间的合法子串,看前面是否是(
elif s[i - 1] == ')' and s[i] == ')':
if i - dst[i - 1] - 1 >= 0 and s[i - dst[i - 1] - 1] == '(':
dst[i] = dst[i - 1] + 2
# 看(前面是否还有合法子串
if i - dst[i - 1] - 2 >= 0:
dst[i] += dst[i - dst[i - 1] - 2]
return max(dst)