【LeetCode-动态规划/栈】最长有效括号
题目描述
给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。
示例:
输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"
题目链接: https://leetcode-cn.com/problems/longest-valid-parentheses/
思路1
使用和有效括号类似的方法。使用一个栈来存储元素的下标:
- 如果当前栈为空或者当前字符 s[i] = '(' 或者栈顶元素为 ')' ,则将当前元素的下标 i 入栈;
- 否则,弹出栈顶元素:
- 如果栈不空,则比较当前的最长括号长度和 i-stack.top() 之间的大小,根据大小情况更新;
- 否则,如果栈空,则比较当前的最长括号长度和 i-(-1) 之间的大小(例如,输入的字符串为
"()"
),根据大小情况更新;
代码如下:
class Solution {
public:
int longestValidParentheses(string s) {
if(s.empty()) return 0;
stack<int> st; // 存储下标
int ans = 0;
for(int i=0; i<s.size(); i++){
if(st.empty() || s[st.top()]==')' || s[i]=='(') st.push(i);
else{
st.pop(); // 注意,要先 pop
int t = st.empty()? -1:st.top();
ans = max(ans, i-t);
}
}
return ans;
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(n)
该方法参考了这篇题解。
思路2
使用动态规划。
- 状态定义:dp[i] 表示前 i 个字符中最长包含有效括号的子串的长度;
- 状态转移:
- 如果 s[i]=='(',则说明 i 是新括号开始的位置,所以 dp[i]=0;
- 如果 s[i]==')':
-
如果 s[i-1]=='(',说明找到了一个括号
()
,则 dp[i] = dp[i-2] + 2;注意这里的 i-1 和 i-2 都不能超数组范围,如果超过范围,则 dp[i]=0;
-
如果 s[i-1]==')',则要判断 s[i-dp[i]-1] 是否是'(',如果是的话,说明我们碰到了类似
(((...)))
的情况,此时 dp[i] = dp[i-1] + 2;因为字符串可能是()(((...)))
这样的情况
,所以要加上 dp[i-dp[i-1]-2]。所以,dp[i] = dp[i-1] + 2 + dp[i-dp[i]-2]。注意,这里的数组下标都不能超过数组范围,如果 i-dp[i]-1 超过了数组范围,则 dp[i]=0;如果 i-dp[i]-2 超过了范围,则 dp[i] = dp[i-1] + 2。
-
这两幅图来自这篇题解。
代码如下:
class Solution {
public:
int longestValidParentheses(string s) {
if(s.empty()) return 0;
int maxLen = -1;
vector<int> dp(s.length(), 0);
for(int i=0; i<s.length(); i++){
if(s[i]=='(') dp[i] = 0;
else if(s[i]==')'){
if(i==0) dp[i] = 0;
else if(s[i-1]=='(') dp[i] = (i>=2? dp[i-2]:0) + 2;
else if(s[i-1]==')'){
if(i-dp[i-1]-1>=0 && s[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;
}
else dp[i] = 0;
}
}
maxLen = max(maxLen, dp[i]);
}
return maxLen;
}
};
- 时间复杂度:O(s.length())
- 空间复杂度:O(s.length())
思路3
使用栈来做,栈用来存储下标。
- 将 -1 入栈;
- 遍历 s:
- 如果 s[i]=='(',则将下标 i 入栈;
- 如果 s[i]==')',则将栈顶元素出栈:
- 如果栈为空,将 i 入栈;
- 否则,计算 i-s.top(),并和当前的最大长度做比较,根据大小情况更新当前的最大长度。
代码如下:
class Solution {
public:
int longestValidParentheses(string s) {
if(s.empty()) return 0;
int maxLen = 0;
stack<int> stk;
stk.push(-1);
for(int i=0; i<s.length(); i++){
if(s[i]=='(') stk.push(i);
else if(s[i]==')'){
stk.pop();
if(stk.empty()) stk.push(i);
else{
maxLen = max(i-stk.top(), maxLen);
}
}
}
return maxLen;
}
};
- 时间复杂度:O(s.length())
- 空间复杂度:O(s.length())