题目链接: https://leetcode.com/problems/longest-valid-parentheses/description/
Description
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.
解题思路
整体思路为动态规划,用数组 dp[i]
记录以 s[i]
为最后一个字符的最长合法括号长度。
首先可以想到,合法的括号要包括 (
和 )
,因此遍历字符串时,若遇到 (
时可以暂时不管,仅当遇到 )
时再来处理。另外,合法的括号主要有两种形式:
()() => s[i] == ')' and s[i - 1] == '('
(()) => s[i] == ')' and s[i - 1] == ')'
先考虑第一种形式,容易想到只需要将 s[i - 2]
为最后一个字符的最长合法括号长度加 2 即可,即 dp[i] = dp[i - 2] + 2
第二种形式稍微复杂一点点,需要定位 s[i]
对应的另一个左括号 (
的位置。因为 dp[i - 1]
记录了以 s[i - 1]
为结尾的最长合法括号长度,那么显然 i - dp[i - 1] - 1
就应该是 s[i]
对应的另一个左括号应该在的位置,dp[i - 1]
就是夹在这对外括号中间的最长合法括号长度。要计算 dp[i]
的话,还要考虑紧挨着这对外括号左侧的最长合法括号长度,因为子串可能为 "()(())"
,因此这种情况 dp[i] = dp[i - 1] + 2 + dp[i - dp[i - 1] - 2]
对于为什么 i - dp[i - 1] - 1
是 s[i]
对应的另一个左括号的位置,举个简单的例子看下。s = "(())"
,当遍历完前三个字符后 dp[] = {0, 0, 2, x}
,x
表示未知。此时来计算最后一个字符 s[3]
对应的 dp[3]
的值,可以看到 s[3]
对应的左括号应该就是下标为 i - dp[i - 1] - 1 = 3 - dp[2] - 1 = 0
的字符 s[0]
。
时间复杂度 O(n)
,空间复杂度 O(n)
,n
为字符串 s
的长度。
Code
class Solution {
public:
int longestValidParentheses(string s) {
int maxLen = 0;
vector<int> dp(s.size());
for (int i = 1; i < s.size(); ++i) {
if (s[i] == ')' && s[i - 1] == '(') {
dp[i] = i > 1 ? dp[i - 2] + 2 : 2;
} else if (s[i] == ')' && s[i - 1] == ')' && s[i - dp[i - 1] - 1] == '(') {
if (i - dp[i - 1] - 2 >= 0)
dp[i] = dp[i - 1] + 2 + dp[i - dp[i - 1] - 2];
else
dp[i] = dp[i - 1] + 2;
}
maxLen = max(dp[i], maxLen);
}
return maxLen;
}
};