题目描述:
Given a string containing just the characters '('
and ')'
, find the length of the longest valid (well-formed) parentheses substring.
For "(()"
, the longest valid parentheses substring is "()"
, which has length = 2.
Another example is ")()())"
, where the longest valid parentheses substring is "()()"
, which has length = 4.
分析:
题意:给定一个只包含 '('
和 ')'
的字符串,查找它包含的最长合法圆括号连续子序列,并返回该长度。
思路:此题是LeetCode 20的进化版本。我们可以采用两种方法来解决这个问题:
① Stack:显而易见是继承了LeetCode 20的思路,这里主要讲区别:Ⅰ. 我们将当前字符与Stack栈顶字符进行比较时,如果匹配,则弹出栈顶字符坐标,如果不匹配,此时也把当前字符坐标压入栈中(坐标是为了方便后期运算);Ⅱ. 我们运用了双指针的技巧:假设字符串长度为n,初始化指针left = -1,right = n,此后不断弹出Stack栈顶元素top,用(right - top - 1)(某个合法子串的长度)的值更新答案,并把指针right更新为top值。重复该操作,直到得到最长长度,返回答案。
时间复杂度为O(n)。
代码:
#include <bits/stdc++.h>
using namespace std;
// stack
// T(n) = O(n)
class Solution {
public:
int longestValidParentheses(string s) {
int n = s.length();
// Exceptional Case:
if(n <= 1){
return 0;
}
stack<int> st;
for(int i = 0; i <= n - 1; i++){
if(st.empty()){
st.push(i);
}
else{
if(s[st.top()] == '(' && s[i] == ')'){
st.pop();
}
else{
st.push(i);
}
}
}
// get answer
int ans = 0;
int left = -1, right = n;
while(!st.empty()){
int top = st.top();
st.pop();
ans = max(ans, right - top - 1);
right = top;
}
ans = max(ans, right - left - 1);
return ans;
}
};
② 动态规划:如下图所示,建立数组dp[n],其中dp[i]表示子字符串s[0→i]的最长匹配子串长度。此处采用动态规划的思想,分为几种情况考虑:
I. 如果s[i] = '(',显然dp[i] = 0(因为合法子串不会以前括号结尾)。
II. 如果s[i] = ')'、s[i - 1] = '(',则s[i - 1→i]匹配,需要考察dp[i-2],递推公式为:dp[i] = (i - 2 >= 0)? dp[i - 2] + 2: 2。
III. 如果s[i] = ')'、s[i - 1] = ')',则计算pre = i - 1 - dp[i - 1]。若s[pre] = '(',则s[pre→i]匹配,我们需要考察dp[pre - 1],递推公式为:dp[i] = (pre - 1 >= 0)? dp[pre - 1] + dp[i - 1] + 2: dp[i - 1] + 2;若s[pre] = ')',则s[pre→i]不匹配,dp[i] = 0。
IV. 最后遍历一遍数组dp[n],得到最长合法子串长度。
时间复杂度为O(n)。
代码:
#include <bits/stdc++.h>
using namespace std;
// Dynamic Programming
// T(n) = O(n)
class Solution {
public:
int longestValidParentheses(string s) {
int n = s.length();
// Exceptional Case:
if(n <= 1){
return 0;
}
// save the delta = '('s - ')'s
vector<int> dp(n, 0);
// DP
for(int i = 1; i <= n - 1; i++){
if(s[i] == '('){
dp[i] = 0;
}
else if(s[i] == ')'){
if(s[i - 1] == '('){
dp[i] = (i - 2 >= 0)? dp[i - 2] + 2: 2;
}
else if(s[i - 1] == ')'){
int pre = i - 1 - dp[i - 1];
if(pre >= 0){
if(s[pre] == '('){
dp[i] = (pre - 1 >= 0)? dp[pre - 1] + dp[i - 1] + 2: dp[i - 1] + 2;
}
else if(s[pre] == ')'){
dp[i] = 0;
}
}
else{
dp[i] = 0;
}
}
}
}
// get answer
int ans = 0;
for(int val: dp){
ans = max(ans, val);
}
return ans;
}
};