最长有效括号
2024年10月9日约 915 字大约 3 分钟
最长有效括号
题意
给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号 子串 的长度。
思路一:栈模拟
用栈模拟一遍,将所有无法匹配的括号的位置全部置 。
例如: "()(()" 的 mark 为 [0, 0, 1, 0, 0]
再例如: ")()((())"的 mark 为 [1, 0, 0, 1, 0, 0, 0, 0]
经过这样的处理后, 此题就变成了寻找最长的连续的 的长度。
代码:
class Solution {
public int longestValidParentheses(String s) {
Deque<Integer> st = new ArrayDeque<>();
int n = s.length();
int[] mark = new int[n];
Arrays.fill(mark, 0);
for (int i = 0; i < n; i++){
if (s.charAt(i) == '(') st.push(i);
else {
// 多余的右括号是不需要的,标记
if (st.isEmpty()) mark[i] = 1;
else st.pop();
}
}
// 未匹配的左括号是不需要的,标记
while (!st.isEmpty()){
mark[st.peek()] = 1;
st.pop();
}
// 寻找标记与标记之间的最大长度
int len = 0, ans = 0;
for (int i = 0; i < n; i++){
if (mark[i] == 1){
len = 0;
continue;
}
len++;
ans = Math.max(ans, len);
}
return ans;
}
}思路二:动态规划
定义 DP 数组:
dp[i]表示以下标为 的字符结尾的最长有效括号的长度判断条件:
s[i] == '('时,s[i]无法和其之前的元素组成有效的括号对,所以dp[i] = 0s[i] == ')'时,需要看其前面对元素来判断是否有有效括号对。s[i − 1] == '(',即s[i]和s[i − 1]组成一对有效括号,有效括号长度新增长度 ,i位置的最长有效括号长度为 其之前2个位置的最长括号长度加上当前位置新增的 ,我们无需知道i − 2位置对字符是否可以组成有效括号对。
那么有:dp[i] = dp[i − 2] + 2s[i − 1] == ')',这种情况下,如果前面有和s[i]组成有效括号对的字符,即形如((....)),那就要求s[i − 1]位置必然是有效的括号对,否则s[i]无法和前面对字符组成有效括号对。
这时,我们只需要找到和s[i]配对的位置,并判断其是否是(即可。和其配对的位置为:i − dp[i − 1] − 1。
如果:s[i − dp[i − 1] −1] == '()':有效括号长度新增长度 ,i位置的最长有效括号长度为i - 1位置的最长括号长度加上当前位置新增的 2,那么有:dp[i] = dp[i − 1] + 2
值得注意的是,i − dp[i − 1] − 1和i组成了有效括号对,这将是一段独立的有效括号序列,如果之前的子序列是形如(...)这种序列,那么当前位置的最长有效括号长度还需要加上这一段。
所以:dp[i] = dp[i − 1] + dp[i − dp[i − 1] − 2] + 2
综上可得:
- 当
s[i] == '('时,dp[i]必然等于 ,因为不可能组成有效的括号; - 当
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
- 若
- 每次循环取最大的
dp[i]即可
- 当
代码:
class Solution {
public int longestValidParentheses(String s) {
int n = s.length();
if (s == null || n == 0) return 0;
int[] dp = new int[n];
int ans = 0;
for (int i = 0; i < n; i++){
if (i > 0 && s.charAt(i) == ')'){
if (s.charAt(i - 1) == '('){
if (i - 2 >= 0){
dp[i] = dp[i - 2] + 2;
} else {
dp[i] = 2;
}
} else if (s.charAt(i - 1) == ')' &&
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] + 2 + dp[i - dp[i - 1] - 2];
} else {
dp[i] = dp[i - 1] + 2;
}
}
}
ans = Math.max(ans, dp[i]);
}
return ans;
}
}