32. Longest Valid Parentheses
题目
Given a string containing just the characters '('
and ')'
, find the length of the longest valid (well-formed) parentheses substring.
Example 1:
Input: "(()"
Output: 2
Explanation: The longest valid parentheses substring is "()"
Example 2:
Input: ")()())"
Output: 4
Explanation: The longest valid parentheses substring is "()()"
解题思路
方法一:动态规划
(1)用L[i]表示以s[i]结尾的(必须包括s[i])的最长有效括号;
(2)初始时,L[0] = 0;
(3)状态转移方程:
- 如果s[i] == ‘(’,则以s[i]结尾的序列必然不合法,因此L[i] = 0;
- 如果s[i] == ‘)’,先找到L[i-1]的最长序列的前一位,下标j = i - 1 - L[i-1]。如果j < 0或者s[j] == ‘)’,说明L[i-1]的最长序列之前没有一个’(‘来与s[i]的’)'匹配,因此L[i] = 0; 如果j >= 0 且 s[j] == ‘(’,则s[j]和s[i]匹配,j与i之间串的长度为L[i-1] + 2,同时j与i之间的串还可以与L[j-1]的串相连(当j-1>=0时)。
(4)最后我们求得了以s中每个元素结尾的最长有效括号,选出最大的即可。
代码如下:
class Solution {
public:
int longestValidParentheses(string s) {
if (s.size() < 2) return 0;
vector<int> L(s.size(), 0);
int maxLen = 0;
for (int i = 1; i < s.size(); i++) {
int j = i - 1 - L[i-1];
if (s[i] == '(' || j < 0 || s[j] == ')'){
L[i] = 0;
}
else {
L[i] = L[i-1] + 2;
if (j - 1 >= 0) {
L[i] += L[j-1];
}
if (L[i] > maxLen){
maxLen = L[i];
}
}
}
return maxLen;
}
};
方法二: 栈
用栈模拟括号的匹配,在遍历串s时,遇到’(‘时,将其下标入栈;遇到’)'时,将栈顶元素出栈,并计算当前匹配的括号的长度。
(1)将栈顶元素作为遍历过程中最后一个未匹配的括号的下标;
(2)初始时,栈顶元素为-1(因为从s下标从0开始,因此-1是初始时最后一个未匹配的括号的下标);
(3)遍历时,当遇到左括号,此时该左括号是最后一个未匹配的括号,因此将其下标入栈;
(4)当遇到右括号时,该右括号可以匹配栈顶下标对应的左括号,因此栈顶元素出栈。此时有两种情况:
- 栈不为空:以该右括号结尾的最长有效括号的起点下标为出栈后栈顶元素+1(栈顶元素是最后一个未匹配的括号的下标),因此以该右括号结尾的最长有效括号的长度为该右括号下标减去栈顶元素值。
- 栈为空:说明该右括号没有匹配左括号,该右括号是多出来的右括号,将其下标入栈作为栈顶元素(作为最后一个未匹配的括号的下标)。
(5)当遍历完串s后,我们得到了以s中每个右括号结尾的串的最长有效括号,选出最大的即可。
代码如下:
class Solution {
public:
int longestValidParentheses(string s) {
if (s.size() < 2) return 0;
stack<int> st;
st.push(-1);
int maxLen = 0;
for (int i = 0; i < s.size(); i++) {
if (s[i] == '(') {
st.push(i);
}
else {
st.pop();
if (st.empty()) {
st.push(i);
}
else {
maxLen = max(maxLen, i - st.top());
}
}
}
return maxLen;
}
};