一.题目要求
给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
二.题目难度
困难
三.输入样例
示例 1:
输入:s = “(()”
输出:2
解释:最长有效括号子串是 “()”
示例 2:
输入:s = “)()())”
输出:4
解释:最长有效括号子串是 “()()”
示例 3:
输入:s = “”
输出:0
提示:
- 0 <= s.length <= 3 * 104
- s[i] 为 ‘(’ 或 ‘)’
四.解题思路
- 有效括号分两种情况:
- ( ) ( ) ()() ()() ,长度为 4 4 4
- ( ( ) ) (()) (()) ,长度为 4 4 4 ,也是有效的
- 状态转移 d p [ i ] dp[i] dp[i] 表示以 i i i 位置作为字符串结尾的情况下,字符串开头向左延伸出连续有效的子串长度
- 考虑上述两种情况后,状态转移的递推如下:
-
i i i 位置为左括号 ( ( ( , 则 d p [ i ] dp[i] dp[i] 一定是 0 0 0 ,因为有效子串必须以右括号 ) ) ) 结束。
-
i i i 位置为右括号 ) ) ) , 此时需要按照 1. 中两种有效括号的形式进行分类讨论:
- i − 1 i - 1 i−1 位置是 左括号 ( ( (,此时 d p [ i ] dp[i] dp[i] 的值为 2 + d p [ i − 2 ] 2\,+\,dp[i-2] 2+dp[i−2] ,若 i − 1 i-1 i−1 小于 0 0 0,则为 2 2 2。
- i − 1 i - 1 i−1 位置是 右括号 ) ) ),此时 d p [ i ] dp[i] dp[i] 的值为公式
d p [ i ] = { 0 i − 1 − d p [ i − 1 ] < 0 或 s [ i − 1 − d p [ i − 1 ] ] = ′ ) ′ d p [ i − 1 ] + 2 ( i − d p [ i − 1 ] − 2 ) < 0 到左边界了 d p [ i − 1 ] + 2 + d p [ i − d p [ i − 1 ] − 2 ] ( i − d p [ i − 1 ] − 2 ) ≥ 0 相当于接上了之前的串 dp[i] =\begin{cases} 0 & i - 1 - dp [i-1] <0 \,或\,s[ \,i - 1 - dp [i-1]] = ')' \\\\dp[i - 1] + 2 & (i - dp [i - 1] - 2) < 0 \,到左边界了 \\ \\dp[i - 1] + 2 +dp[i - dp [i - 1] - 2] & (i - dp [i - 1] - 2) \geq 0 \,相当于接上了之前的串 \end{cases} dp[i]=⎩ ⎨ ⎧0dp[i−1]+2dp[i−1]+2+dp[i−dp[i−1]−2]i−1−dp[i−1]<0或s[i−1−dp[i−1]]=′)′(i−dp[i−1]−2)<0到左边界了(i−dp[i−1]−2)≥0相当于接上了之前的串
对应三种情况:
-
五.代码实现
class Solution {
public:int longestValidParentheses(string s) {vector<int> dp(s.size(), 0);int len = 0;//dp[i] : 子串必须以i位置的字符结尾的情况下,往左最多推多远能整体有效for(int i = 1; i < s.size(); i++){if(s[i] == ')'){if(s[i - 1] == '('){dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;}else if(s[i - 1] == ')'){if(i - 1 - dp [i - 1] >= 0 && s[i - 1 - dp [i - 1]] == '(')dp[i] = dp[i - 1] + 2 + ((i - dp [i - 1] - 2) >= 0 ? dp[i - dp [i - 1] - 2] : 0);}}len = max(dp[i] , len);}//for(auto v:dp) cout<<v<<endl;return len;}
};
六.题目总结
–