LC32:最长有效括号
LC32:最长有效括号
题目描述
给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
示例 1:
1
2
3
输入:s = "(()"
输出:2
解释:最长有效括号子串是 "()"
示例 2:
1
2
3
输入:s = ")()())"
输出:4
解释:最长有效括号子串是 "()()"
示例 3:
1
2
输入:s = ""
输出:0
提示:
0 <= s.length <= 3 * 10^4s[i]为'('或')'
分析
解法一:栈
括号问题首先想到的就是用栈。我们可以扫描字符串,遇到 '(' 则入栈,遇到 ')' 则匹配栈中元素并出栈。有两个问题需要考虑:1)如何处理多余的左括号?2)如何在遇到未匹配的右括号时重置计数器?
为了解决这两个问题,我们将入栈的元素选定为 '(' 在字符串中的下标。
- 对于问题 1),在计算有效字串长度时,使用
')'的下标 减去 栈顶元素,避免重复计算; - 对于问题 2),我们将最后遇到的未匹配
')'的下标放入栈底,在遇到')'且栈中只有一个元素(即最后一个')'下标)时,更新栈底元素的值为新遇到的')'下标,这样在计算有效长度时会被该值截断,防止计算多余长度。
整体流程如下:
- 初始化栈(加入
-1作为默认的')'下标) - 扫描字符串
- 遇到
'(':将其下标入栈 - 遇到
')':- 栈中只有栈底元素:更新栈底元素
- 否则,弹出一个
'(',计算有效长度并更新结果
- 遇到
解法二:动态规划
这题也可以考虑使用动态规划进行分析。
使用一个 dp 数组记录下以第 i 位结尾的有效子串长度,下面来分析转移方程。
- 若第
i位为'(',以第i位结尾的字符串必然不合法,因此dp[i] = 0 - 若第
i位为')',则需往前找与其匹配的'(':- 若第
i - 1位为'(',则直接匹配,加上'('之前的有效子串长度,dp[i] = dp[i - 2] + 2; - 若第
i - 1位为')',则我们需要找到以第i - 1位为结尾的有效子串的前一位,即第i - dp[i - 1] - 1位,若为'(',则匹配成功,dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2。注意不要漏项。
- 若第
dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2看起来很复杂,其实很简单,我们逐项分析:
dp[i - 1]为以第i - 1位结尾的有效串长度;dp[i - dp[i - 1] - 2]:以第i - 1位结尾的有效串起始位为i - dp[i - 1],则以第i位结尾的有效串的前一个有效串的结尾为第i - dp[i - 1] - 2位,该串长度为dp[i - dp[i - 1] - 2];- 本身两个括号占两个长度。
因此,
dp[i]即为这三项加起来之和。
计算转移方程时,注意确保下标大于等于 0.
实现
解法一:栈
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public int longestValidParentheses(String s) {
Stack<Integer> stk = new Stack<>();
stk.push(-1);
int maxans = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
stk.push(i);
continue;
}
if (stk.size() > 1) {
stk.pop();
maxans = Math.max(maxans, i - stk.peek());
} else {
stk.pop();
stk.push(i);
}
}
return maxans;
}
}
解法二:动态规划
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
29
30
31
32
class Solution {
public int longestValidParentheses(String s) {
if (s.length() == 0)
return 0;
int[] dp = new int[s.length()];
dp[0] = 0;
int ans = 0;
for (int i = 1; i < s.length(); i++) {
if (s.charAt(i) == '(') {
dp[i] = 0;
continue;
}
if (s.charAt(i - 1) == '(') {
if (i >= 2)
dp[i] = dp[i - 2] + 2;
else
dp[i] = 2;
}
else if (i - dp[i - 1] - 1 >= 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
if (i - dp[i - 1] - 2 >= 0)
dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2;
else
dp[i] = dp[i - 1] + 2;
}
else
dp[i] = 0;
if (dp[i] > ans)
ans = dp[i];
}
return ans;
}
}
This post is licensed under CC BY 4.0 by the author.

