32. Longest Valid Parentheses (H)
Given a string containing just the characters '('
and ')'
, find the length of the longest valid (well-formed) parentheses substring.
Example 1:
Input: s = "(()"
Output: 2
Explanation: The longest valid parentheses substring is "()".
Example 2:
Input: s = ")()())"
Output: 4
Explanation: The longest valid parentheses substring is "()()".
Example 3:
Input: s = ""
Output: 0
Constraints:
0 <= s.length <= 3 * 104
s[i]
is'('
, or')'
.
Solution:
Version 1: Stack
1.遍历给字符串中的所有字符 1.1若当前字符sindex为左括号'(',将当前字符下标index入栈(下标稍后有其他用处),处理下一字符 1.2若当前字符sindex为右括号')',判断当前栈是否为空 1.2.1若栈为空,则accumulatedLen = 0,当前有效长度为0,处理下一字符(当前字符右括号下标不入栈) 1.2.2若栈不为空,则出栈(由于仅左括号入栈,则出栈元素对应的字符一定为左括号,可与当前字符右括号配对),判断栈是否为空 1.2.2.1若栈为空,则maxlen = max(maxlen, index-start+1),更新当前最大匹配序列长度 1.2.2.2若栈不为空,则maxlen = max(maxlen, i-栈顶元素值),更新当前最大匹配序列长度
Version2: dp
题解: 一般对于最长XX问题容易想到利用DP求解,在这题中利用逆向DP,设状态dpi为从i到len - 1中,以i开头的最长合法子串长度:
Version 3: Stack + dp
如果你看过前文 手把手解决三道括号相关的算法题,就知道一般判断括号串是否合法的算法如下:
Stack<Integer> stk = new Stack<>();
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
// 遇到左括号,记录索引
stk.push(i);
} else {
// 遇到右括号
if (!stk.isEmpty()) {
// 配对的左括号对应索引,[leftIndex, i] 是一个合法括号子串
int leftIndex = stk.pop();
// 这个合法括号子串的长度
int len = 1 + i - leftIndex;
} else {
// 没有配对的左括号
}
}
}
但如果多个合法括号子串连在一起,会形成一个更长的合法括号子串,而上述算法无法适配这种情况。
所以需要一个 dp
数组,记录 leftIndex
相邻合法括号子串的长度,才能得出题目想要的正确结果。
class Solution {
public int longestValidParentheses(String s) {
Stack<Integer> stk = new Stack<>();
// dp[i] 的定义:记录以 s[i-1] 结尾的最长合法括号子串长度
int[] dp = new int[s.length() + 1];
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
// 遇到左括号,记录索引
stk.push(i);
// 左括号不可能是合法括号子串的结尾
dp[i + 1] = 0;
} else {
// 遇到右括号
if (!stk.isEmpty()) {
// 配对的左括号对应索引
int leftIndex = stk.pop();
// 以这个右括号结尾的最长子串长度
int len = 1 + i - leftIndex + dp[leftIndex];
dp[i + 1] = len;
} else {
// 没有配对的左括号
dp[i + 1] = 0;
}
}
}
// 计算最长子串的长度
int res = 0;
for (int i = 0; i < dp.length; i++) {
res = Math.max(res, dp[i]);
}
return res;
}
}
Last updated
Was this helpful?