2020-03-31 14:09:20 +00:00
|
|
|
|
# [32. Longest Valid Parentheses](https://leetcode.com/problems/longest-valid-parentheses/)
|
|
|
|
|
|
|
|
|
|
# 思路
|
|
|
|
|
|
|
|
|
|
求有效括号匹配子串的最大长度。
|
|
|
|
|
|
|
|
|
|
## 思路一、栈
|
|
|
|
|
|
|
|
|
|
括号匹配类的问题往往都能用栈解决,此题也不例外。
|
|
|
|
|
|
|
|
|
|
从前往后遍历字符串,设下标为i
|
|
|
|
|
* 如果遇到左括号或者栈空,则将当前下标i压入栈;
|
|
|
|
|
* 如果遇到右括号且栈顶为左括号,则遇到了匹配的括号对,将栈顶弹出即可;
|
|
|
|
|
|
2020-06-18 01:22:15 +00:00
|
|
|
|
然后就可以计算以字符`s[i]`作为结尾的最大长度:
|
|
|
|
|
* 若栈不空,则长度为`i - stk.top()`;
|
|
|
|
|
* 否则,即栈空,说明前面的都能匹配,则长度为`i+1`。
|
2020-03-31 14:09:20 +00:00
|
|
|
|
|
|
|
|
|
时空复杂度均为O(n)
|
|
|
|
|
|
|
|
|
|
## 思路二、动归
|
|
|
|
|
|
|
|
|
|
由于此问题存在很多子问题,且子问题之前又有很多重复,所可以考虑用动归。
|
|
|
|
|
|
|
|
|
|
先来看状态定义:
|
|
|
|
|
```
|
|
|
|
|
dp[i]: 以字符s[i]结尾的最大匹配长度
|
|
|
|
|
```
|
|
|
|
|
状态转移方程就很简单了:
|
|
|
|
|
* 如果`s[i] = '('`,那么`dp[i] = 0`;
|
|
|
|
|
* 否则,我们需要看以字符`s[i-1]`为结尾的最大匹配子串的前面那个字符`s[i - dp[i-1] - 1]`是否是左括号:
|
|
|
|
|
* 若是,说明匹配上了,所以`dp[i] = dp[i-1] + 2 + dp[i - dp[i-1] - 2]`;
|
|
|
|
|
* 若不是,则没匹配上,`dp[i] = 0`。
|
|
|
|
|
|
|
|
|
|
时空复杂度均为O(n)
|
|
|
|
|
|
|
|
|
|
## 思路三
|
|
|
|
|
|
|
|
|
|
前面两种思路的空间复杂度均为O(n),此题还有一种常数空间的思路,和前面栈的思想有点类似。
|
|
|
|
|
|
|
|
|
|
使用两个变量left和right分别用来记录到当前位置时左括号和右括号的出现次数,当遇到左括号时,left自增1;否则right自增1。
|
|
|
|
|
|
|
|
|
|
* 当`left == right`时,说明匹配成功,此时匹配长度为`2*left`;
|
|
|
|
|
* 一旦遇到`right > left`,说明当前位置不能匹配,则重新开始,即left和right均重置为0。
|
|
|
|
|
|
|
|
|
|
但是对于"(()"这种时,在遍历结束时左右子括号数都不相等,此时没法更新结果res,但其实正确答案是2,怎么处理这种情况呢?答案是再反向遍历一遍,采取类似的方法,稍有不同的是此时若`right < left`了,则重置0。
|
|
|
|
|
|
|
|
|
|
时间复杂度O(n),空间复杂度O(1)
|
|
|
|
|
|
|
|
|
|
# C++
|
|
|
|
|
|
|
|
|
|
## 思路一
|
|
|
|
|
``` C++
|
|
|
|
|
class Solution {
|
|
|
|
|
public:
|
|
|
|
|
int longestValidParentheses(string s) {
|
|
|
|
|
stack<int>stk;
|
|
|
|
|
int res = 0, start = 0;
|
|
|
|
|
for(int i = 0; i < s.size(); i++){
|
|
|
|
|
if(!stk.empty() && s[stk.top()] == '(' && s[i] == ')') stk.pop();
|
|
|
|
|
else stk.push(i);
|
|
|
|
|
// 栈顶为当前匹配子串的起始位置
|
|
|
|
|
res = max(res, stk.empty() ? i + 1 : i - stk.top());
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 思路二
|
|
|
|
|
``` C++
|
|
|
|
|
class Solution {
|
|
|
|
|
public:
|
|
|
|
|
int longestValidParentheses(string s) {
|
|
|
|
|
vector<int>dp(s.size(), 0);
|
|
|
|
|
int res = 0;
|
|
|
|
|
for(int i = 1; i < s.size(); i++){
|
|
|
|
|
if(s[i] == '(') continue;
|
|
|
|
|
int tmp = i - dp[i-1] - 1;
|
|
|
|
|
if(tmp >= 0 && s[tmp] == '(')
|
|
|
|
|
dp[i] = dp[i-1] + 2 + (tmp >= 1 ? dp[tmp - 1] : 0);
|
|
|
|
|
res = max(res, dp[i]);
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 思路三
|
|
|
|
|
``` C++
|
|
|
|
|
class Solution {
|
|
|
|
|
public:
|
|
|
|
|
int longestValidParentheses(string s) {
|
|
|
|
|
int res = 0, left = 0, right = 0, n = s.size();
|
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
|
if(s[i] == '(') left++;
|
|
|
|
|
else right++;
|
|
|
|
|
if (left == right) res = max(res, 2 * right);
|
|
|
|
|
else if (right > left) left = right = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
left = right = 0;
|
|
|
|
|
for (int i = n - 1; i >= 0; i--) {
|
|
|
|
|
if(s[i] == '(') left++;
|
|
|
|
|
else right++;
|
|
|
|
|
if (left == right) res = max(res, 2 * left);
|
|
|
|
|
else if (left > right) left = right = 0;
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
};
|
2020-06-18 01:22:15 +00:00
|
|
|
|
```
|