今天给大家带来一道leetcode经典题,最长有效括号,本文将介绍动态规划解法解法,希望对你有所帮助。这是动态规划系列的最后一题了,想要看之前动态规划的题解的小伙伴可以去热题100专栏获取🍗🍖🥩
题目
给你一个只包含 '('
和 ')'
的字符串,找出最长有效(格式正确且连续)括号
子串的长度。
示例 1:
输入:s = "(()" 输出:2 解释:最长有效括号子串是 "()"
示例 2:
输入:s = ")()())" 输出:4 解释:最长有效括号子串是 "()()"
示例 3:
输入:s = "" 输出:0
提示:
s[i]
为'('
或')'
思路
要找到字符串中最长的有效括号子串,我们可以使用动态规划的方法。我们定义一个数组dp,dp[i]的含义是字符串的第i位上最长的最长有效括号子串的长度。
我们从前往后遍历字符串求解 dp 值,我们每两个字符检查一次:
- 如果s[i]=‘)’ 且 s[i−1]=‘(’,也就是字符串形如 “……()”,我们可以推出:
dp[i]=dp[i−2]+2
我们可以进行这样的转移,是因为结束部分的 "()" 是一个有效子字符串,并且将之前有效子字符串的长度增加了 2 。
- 如果s[i]=‘)’ 且 s[i−1]=‘)’,也就是字符串形如 “……))”,我们可以推出:
如果 s[i−dp[i−1]−1]=‘(’,那么,
dp[i]=dp[i−1]+dp[i−dp[i−1]−2]+2
此时 s[i−dp[i−1]−1]和s[i]构成一堆字符串 “()”,所以我们+2
我们还需要加上s[i−dp[i−1]−1]之前一个位置的构成括号的数目,即dp[i−dp[i−1]−2]
在 i-dp[i-1]-1 和 i-1之间还有一段字符串,这段字符串所组成的符合要求的字符串长度就是dp[i-1]
通过上面的转移思想从后往前递推,就能得到我们想要的答案
方法
-
初始化一个长度为字符串长度的
dp
数组,初始值全为 0。 -
从第二个字符开始遍历字符串,对于每个字符:
- 如果字符是右括号
)
:- 检查它的前一个字符是否是左括号
(
。如果是,则它们可以组成一对有效的括号子串,更新dp[i] = dp[i-2] + 2
(如果i-2
小于 0,则dp[i-2]
为 0)。 - 如果前一个字符也是右括号
)
,则需要检查i - dp[i - 1] - 1
位置上的字符是否是左括号(
,如果是,则可以将当前有效括号子串的长度加上,更新dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2
(如果i - dp[i - 1] - 2
小于 0,则dp[i - dp[i - 1] - 2]
为 0)。
- 检查它的前一个字符是否是左括号
- 如果字符是右括号
-
最后返回
dp
数组中的最大值,即为最长有效括号子串的长度。
代码
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 if i >= 2 else 2
elif i - dp[i - 1] > 0 and s[i - dp[i - 1] - 1] == '(':
dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2 if i - dp[i - 1] >= 2 else dp[i - 1] + 2
return max(dp)