题目分析
题目链接:32. Longest Valid Parentheses
输入的字符串s由'('和')'组成,其中存在一些子串是合法的括号字符串。
比如(()())
是合法的括号字符串;()())(())
就不是合法的括号字符串,但是其中的()()
和(())
是合法的括号字符串。
原题目要求找到最长合法括号子串的长度,但是我们提出进一步的要求:找出其中的所有合法括号子串。找出了所有合法括号子串,最长子串的长度自然也能得到。
题解1:利用栈找出所有合法括号子串
表示嵌套关系的最好方式就是栈。比如函数调用,比如括号匹配。
合法括号字符串的一个充分必要条件是:将其中字符压入栈中,如果压入)
时栈顶恰好是(
,那么将这两个字符都出栈(它们组成一个括号),压入所有字符以后栈是空的。
因此我们可以将输入字符串s的所有字符依次按照这种方式压入栈中,其中构成括号的子串会自己抵消,最终留在栈中的字符是所有没有被匹配的)
或(
。在s中,在这些没有被匹配的字符之间,就是合法的括号字符串。
代码实现
class Solution
{
public:
int longestValidParentheses(string s)
{
stack<int> sta;
for (int i = 0; i < s.size(); i++)
{
// 将输入字符依次压入栈中
if (s[i] == '(')
{
sta.push(i);
}
else if (s[i] == ')')
{
if (sta.size() > 0)
{
if (s[sta.top()] == '(')
{
// 相匹配的)和(相互抵消,最后栈中只剩下没有匹配的)和(
sta.pop();
}
else
{
sta.push(i);
}
}
else
{
// 如果)是栈中第一个元素,那么它必定没有匹配
sta.push(i);
}
}
}
int start, end = s.size(), length = 0, max_length = 0;
while (sta.size() > 0)
{
start = sta.top();
sta.pop();
// 在s中,在没有匹配的)和(之间,就是那些被匹配抵消的符号
length = end - start - 1;
if (length > max_length)
max_length = length;
end = start;
}
// 栈中最后剩余的符号之前,也是合法的括号子串
length = end;
if (length > max_length)
max_length = length;
return max_length;
}
};
时间复杂度
该算法先扫描一遍s再扫描一遍栈中的剩余元素,每一次针对扫描的值仅仅做O(1)的简单计算,因此总的时间复杂度为O(n)。
题解2:动态规划,利用s[i]之前的匹配情况帮助计算s[i]的匹配情况。
使用一个数组longest,longest[i]存储以s[i]结尾的最长括号子串的长度。比如对于s:()())(())
,longest为[0,2,0,4,0,0,0,2,4]。
只要算出了longest,我们就能得到每个括号子串。如果longest[k]==n那么就存在一个合法括号子串:s[k-n+1]~s[k]。
那么如何计算longest呢?我们利用动态规划的思想:从longest[0]开始,利用s[0]~s[i-1]和longest[0]~longest[i-1]的值,来计算longest[i]的值:
- 如果s[i]==
(
,那么longest[i] = 0。因为以(
结尾的必定不是合法的括号字符串。 -
如果s[i]==
)
:- 如果s[i-1]==
(
,那么longest[i] = longest[i-2] + 2。 -
如果s[i-1]==
)
:- 如果s[i-longest[i-1]-1]==
(
,那么longest[i] = longest[i-1] + 2 + longest[i-longest[i-1]-2]。 - 否则longest[i] = 0。
- 如果s[i-longest[i-1]-1]==
- 如果s[i-1]==
代码实现
class Solution
{
public:
int longestValidParentheses(string s)
{
int size = (int)s.size(), current_max = 0;
vector<int> longest(size, 0);
for (int i = 1; i < size; i++)
{
if (s[i] == '(')
{
longest[i] = 0;
}
else
{
// s[i]==')'
if (s[i - 1] == '(')
{
longest[i] = i - 2 >= 0 ? (longest[i - 2] + 2) : 2;
current_max = longest[i] > current_max ? longest[i] : current_max;
}
else
{
// s[i-1]==')'
if (i - longest[i - 1] - 1 >= 0 && s[i - longest[i - 1] - 1] == '(')
{
longest[i] = (i - longest[i - 1] - 2 >= 0) ? (longest[i - 1] + 2 + longest[i - longest[i - 1] - 2]) : (longest[i - 1] + 2);
current_max = longest[i] > current_max ? longest[i] : current_max;
}
else
{
longest[i] = 0;
}
}
}
}
return current_max;
}
};
时间复杂度
该算法仅仅对每个字符做一次O(1)的简单计算,因此时间复杂度也是O(n)。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。