算法分析与设计,第19周博客
32. Longest
Valid Parentheses
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.
给出一个只包含左括号 '(' 和右括号 ')' 的字符串,要求出其中最长的括号匹配的子串的长度。
关于括号匹配的问题,一般都可以用stack来解决,这题也一样,不过,在这里,并不介绍使用stack解决的方法,而是给出动态规划的解决方法。
构造这样一个dp数组,其中dp[i] 表示以s[i]结尾的最长合法括号的长度,那么,这样得出整个dp数组后,只需遍历一次就可以得出其中最大的值,也就是题目的最长合法子串的长度。
当s[i] == '(',也就是子串以左括号结尾时,这时的子串是不合法的,所以dp[i] = 0;
当 s[i] == ')',子串以右括号结尾,有可能是合法的,但是具体是否合法,以及相应的长度还与之前一个字符有关:
- s[i-1] == '(',此时,s[i-1] 和s[i]匹配,所以以s[i]结尾的子串存在合法匹配,再把这两个字符之前的匹配长度相加就得到了当前的长度,dp[i] = 2+dp[i-2];
- s[i-1] == ')',此时,需要把到s[i-1]为止的子串都剔除,再进一步判断之前的那个字符是否是左括号,从而判断是否合法并进一步计算其长度。设剔除完s[i-1]的前缀子串后的第一个字符的下标是left,那么,如果s[left] == '(',那么有 dp[i] = 2+dp[i-1]+dp[left-1];
class Solution {
public:
int longestValidParentheses(string s) {
int longest = 0, cur = 0, left = 0;
int n = s.length();
vector<int> dp(n+1, 0);
for (int i = 0; i < n; ++i) {
if (s[i] == ')' && i > 0) {
if (s[i-1] == '(') {
dp[i] = i < 2 ? 2 : 2+dp[i-2];
longest = max(longest, dp[i]);
} else {
left = i-dp[i-1]-1;
if (left >= 0 && s[left] == '(')
{
dp[i] = left > 0 ? 2+dp[i-1]+dp[left-1] : 2+dp[i-1];
}
}
longest = max(longest, dp[i]);
}
}
return longest;
}
};
最后来看下时间复杂度,存在一个循环,循环中有个操作都是需要常数时间,所以时间复杂度是O(n)。