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.
解法一、利用栈,时间复杂度为O(n),空间复杂度为O(n)。
基本思想:从头开始遍历字符串,遇到左括号则做入栈,遇到右括号则出栈。一个右括号能消去一个左括号。
不同的是,为了能够计算括号对的长度,还需要记录括号的下标。
当弹出一个左括号后,根据当前坐标减去栈中上一个(也就是pop之后的top元素)的坐标,可得到该有效括号对的长度。
//新建结构体,保存字符及下标
struct Node
{ char c;
int index;
Node() {}
Node(char sc,int i)
{
this->c=sc;
this->index=i;
}
};
class Solution
{
public:
int max(int a,int b)
{
return a>b?a:b;
}
int longestValidParentheses(string s)
{
stack<Node> sta;
int ret=0;
for(int i=0;i<s.size();i++)
{
char sc=s[i];
if(sc=='(')//遇到左括号,则入栈
sta.push(Node(sc,i));
else
{
if(!sta.empty()&&sta.top().c=='(')
{//当栈不为空,并且栈顶元素为左括号时
int curlen;
sta.pop();//出栈
if(sta.empty())
{
curlen=i+1;//当出栈后,栈为空。说明已遍历过的字符串完全匹配
}
else
{
curlen=i-sta.top().index;//当前下标减去栈顶元素对应下标
}
ret=max(ret,curlen);//更新匹配子串的最大值
}
else//当遇到右括号,栈为空或者栈顶同为右括号,则入栈
sta.push(Node(sc,i));
}
}
return ret;
}
};
解法二、动态规划法,时间复杂度为O(n),空间复杂度为O(n)。
利用一维数组逆向求解,求最长合法匹配的长度。
假设输入字符串S,长度为n。维护一个长度为n的一维数组dp[n],初始化值为0。
dp[i]表示从S[I]到S[n-1],包含S[i]的最长有效匹配括号子串长度。
则:
dp[n-1]=0;
从i=n-2逆向求dp[i],并记录最大值。若S[i]==’(’,要想计算dp[i]的值,计算在S中,从i开始到n-1的子串。分两步计算:
STEP1:在S中寻找从i+1开始的有效括号匹配字串长度,即dp[i+1]。跳过此段已经匹配的子串,查看下一个字符,其下标为j=i+1+dp[i+1]。若j未越界,并且S[j]==’)’,则s[i,...j]为有效匹配的子串,即dp[i]=dp[i+1]+2;
STEP2:求得匹配子串S[i,...j]之后,若j+1未越界,则dp[i]的值还要加上从j+1开始的最长有效匹配。即dp[j+1]。
class Solution
{
public:
int max(int a,int b)
{
return a>b?a:b;
}
int longestValidParentheses(string s)
{
int n=s.size();
if(n<2) return 0;
int dp[n];//动态规划
for(int i=0;i<n;i++)
dp[i]=0;//初值为0
int maxlen=0;
for(int i=0;i<s.size();i++)
{
if(s[i]=='(')
{
int j=i+1+dp[i+1];
if(j<n&&s[j]==')')
{
dp[i]=dp[i+1]+2;
if(j+1<len)
dp[i]+=dp[j+1];
}
}
//更新匹配最长字串长度
maxlen=max(maxlen,dp[i]);
}
return maxlen;
}
};