给你一个只包含’(’ 和’)'的字符串,找出最长有效(格式正确且连续)括号子串的长度。
输入:s = “)()())”
输出:4
解释:最长有效括号子串是 “()()”
思路一:动态规划
将dp数组初始化为全0。
当遇到某个字符为" ) "时,更新dp数组的值。
-
情况一:
s[i - 1] == " ( ",即s[i] 和s[i - 1]组成一对有效括号,有效括号长度新增长度2,i位置对的最长有效括号长度为其之前2个位置的最长括号长度加上当前位置新增的2,我们无需知道i - 2位置对字符是否可以组成有效括号对。 -
情况二:
s[ i - 1] == " ) "。这种情况下,如果前面有和s[i]组成有效括号对的字符,即形如((……)),这样的话,就要求s[i - 1]位置必然是有效括号对,否则s[i]无法和前面对字符组成有效括号对。
这时,我们只需要找到和s[i]配对对位置,并判断其是否是 ( 即可。由于i-1处的 ( 必然有一个 ) 与之对应,就两种情况,要么i-2处是 ( 与 i-1处的 ) 对应上,要么i-2处还是 ) ,要跟i-3处的 ( 对应上,然后还要保证i-4处的也是 (,当然,i-4处有可能不是了,那就不满足条件,这我后面会讲到。然后,我们假定已经知道dp[i-1]的大小,也就是前面已经有几个有效括号对了,比如 ( ) ( ( ) ) ,在求最后一个括号dp[i]的时候,dp[i-1]已经知道是2(形成一对有效括号+2,而不是+1)。此时为了找最后一个右括号的左括号,需要向前移动三个单位长度,因为这表明有内部括号,然后需要跳到内部括号的最前面去找。好了,这样的话i - dp[i-1] - 1就是与i处的右括号对应的左括号的位置了。
那么有:dp[i] = 2 + dp[ i - 1] + dp[ i - dp[i-1] -2 ]
其中第2项代表内部括号,第3项代表内部括号前面还有没有独立的有效括号组。可以看到,刚刚分析了这么多,分析出来了i - dp[i-1] - 1的目的就是为了找到 i - dp[i-1] -2 的!。
class Solution
{
public:
int longestValidParentheses(string s)
{
int size = s.size();
vector<int> dp(size, 0);
int maxVal = 0;
// 注意!!注意!!i = 1开始,因为后面有s[i-1],否则会字符串越界!!!!
for (int i = 1; i < size; i++)
{
if (s[i] == ')')
{
if (s[i - 1] == '(')
{
dp[i] = 2;
if (i - 2 >= 0)
{
dp[i] = dp[i] + dp[i - 2];
}
}
else if (dp[i - 1] > 0) // 有子有效括号组
{
if ((i - dp[i - 1] - 1) >= 0 && s[i - dp[i - 1] - 1] == '(') // 防止越界并且找到了对应位置上的左括号
{
dp[i] = dp[i - 1] + 2;
if ((i - dp[i - 1] - 2) >= 0)
{
dp[i] = dp[i] + dp[i - dp[i - 1] - 2];
}
}
}
}
maxVal = max(maxVal, dp[i]);
}
return maxVal;
}
};