题目
给你一个只包含 ‘(‘ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
示例 1:
输入:s = “(()”
输出:2
解释:最长有效括号子串是 “()”示例 2:
输入:s = “)()())”
输出:4
解释:最长有效括号子串是 “()()”示例 3:
输入:s = “”
输出:0提示:
0 <= s.length <= 3 * 10^4
s[i] 为 ‘(‘ 或 ‘)’来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-valid-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
方法一:参考「热评」的解法,先利用栈将无法匹配的括号标识出来,比如可以将该下标位置为1,然后就转化为了求连续最长的0的长度,见代码一。
方法二:动态规划,dp[i]表示以i位置结尾的最长的有效括号长度,首先i处的字符必须是右括号,接下来讨论dp[i]值为多少,如果i-1处为左括号,那么dp[i]=dp[i-1]+2,这一点好理解,如果i-1处不是左括号,就需要找到和i这个右括号匹配的左括号(也可能不存在匹配的左括号),这个左括号如果存在的话,一定在和i-1匹配的左括号的左边,例如,如果dp[i-1]为2,那么i处往前dp[i-1]+1即往前3位就是要找的左括号(仍然要注意是可能为左括号),下标即i-dp[i-1]-1,以这个左括号左边的括号结尾的dp[i-dp[i-1]-2]加上i-dp[i-1]-1到i的长度就是dp[i]了,写成公式就是dp[i]=dp[i-dp[i-1]-2]+dp[i-1]+2。自己也觉得描述的很是乱,看代码吧还是。
代码
代码一 栈+数组
class Solution {
public int longestValidParentheses(String s) {
int n = s.length();
int[] arr = new int[n];
Deque<Integer> stack = new ArrayDeque<>();
for (int i = 0; i < n; i++) {
if (s.charAt(i) == '(') {
stack.push(i);
} else {
if (!stack.isEmpty() && s.charAt(stack.peek()) == '(') {
stack.poll();
} else {
// 当前右括号无法匹配
arr[i] = 1;
}
}
}
// 最后栈中为未匹配的左括号
while (!stack.isEmpty()) {
arr[stack.poll()] = 1;
}
// 将无法匹配的括号都标记为1,最后就是求最长的连续的0长度
int ans = 0;
int cnt = 0;
for (int i = 0; i < n; i++) {
if (arr[i] == 0) {
cnt++;
ans = Math.max(ans, cnt);
} else {
cnt = 0;
}
}
return ans;
}
}
代码二 DP
class Solution {
public int longestValidParentheses(String s) {
int n = s.length();
int[] arr = new int[n];
int ans = 0;
// dp[i]表示以第i位结尾的最长有效括号的长度,i属于[1,n]
int[] dp = new int[n + 1];
for (int i = 2; i <= n; i++) {
if (s.charAt(i - 1) == ')') {
if (s.charAt(i - 2) == '(') {
dp[i] = dp[i - 2] + 2;
// i 往前 dp[i - 1] + 1 位是i匹配的左括号,在dp中下标为i - dp[i - 1] - 1,在s中还需要偏移一个下标,因此对于s来说是i - dp[i - 1] - 2
} else if (i - dp[i - 1] - 2 >= 0 && s.charAt(i - dp[i - 1] - 2) == '(') {
// dp[i-1]+2是i - dp[i - 1] - 1到i的长度,dp[i - dp[i - 1] - 2]是以i - dp[i - 1] - 1的左边括号结尾的最长有效长度
dp[i] = dp[i - 1] + 2 + dp[i - dp[i - 1] - 2];
}
ans = Math.max(ans, dp[i]);
}
}
return ans;
}
}