32. 最长有效括号
题目描述
给你一个只包含 '('
和 ')'
的字符串,找出最长有效(格式正确且连续)括号子串的长度。
示例 1:
输入:s = "(()" 输出:2 解释:最长有效括号子串是 "()"
示例 2:
输入:s = ")()())" 输出:4 解释:最长有效括号子串是 "()()"
示例 3:
输入:s = "" 输出:0
提示:
0 <= s.length <= 3 * 104
s[i]
为'('
或')'
解法
方法一:动态规划
我们定义 $f[i]$ 表示以 $s[i-1]$ 结尾的最长有效括号的长度,那么答案就是 $\max\limits_{i=1}^n f[i]$。
- 如果 $s[i-1]$ 是左括号,那么以 $s[i-1]$ 结尾的最长有效括号的长度一定为 $0$,因此 $f[i] = 0$。
- 如果 $s[i-1]$ 是右括号,有以下两种情况:
- 如果 $s[i-2]$ 是左括号,那么以 $s[i-1]$ 结尾的最长有效括号的长度为 $f[i-2] + 2$。
- 如果 $s[i-2]$ 是右括号,那么以 $s[i-1]$ 结尾的最长有效括号的长度为 $f[i-1] + 2$,但是还需要考虑 $s[i-f[i-1]-2]$ 是否是左括号,如果是左括号,那么以 $s[i-1]$ 结尾的最长有效括号的长度为 $f[i-1] + 2 + f[i-f[i-1]-2]$。
因此,我们可以得到状态转移方程:
$$ \begin{cases} f[i] = 0, & \textit{if } s[i-1] = '(',\ f[i] = f[i-2] + 2, & \textit{if } s[i-1] = ')' \textit{ and } s[i-2] = '(',\ f[i] = f[i-1] + 2 + f[i-f[i-1]-2], & \textit{if } s[i-1] = ')' \textit{ and } s[i-2] = ')' \textit{ and } s[i-f[i-1]-2] = '(',\ \end{cases} $$
最后返回 $\max\limits_{i=1}^n f[i]$ 即可。
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为字符串的长度。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
方法二:使用栈
- 使用栈来存储左括号的索引,栈底元素初始化为
-1
,用于辅助计算有效括号的长度。 - 遍历字符串,对于每个字符:
- 如果是左括号,将当前位置压入栈。
- 如果是右括号,弹出栈顶元素表示匹配了一个左括号。
- 如果栈为空,说明当前右括号无法匹配,将当前位置压入栈作为新的起点。
- 如果栈不为空,计算当前有效括号子串的长度,更新最大长度。
- 最终返回最大长度。
总结:这个算法的关键在于维护一个线,栈内存放的是左括号的索引,通过弹出和压入的操作来更新有效括号子串的长度。
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为字符串的长度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|