给你一个只包含 '('
和 ')'
的字符串,找出最长有效(格式正确且连续)括号子串
的长度。
示例 1:
输入:s = "(()" 输出:2 解释:最长有效括号子串是 "()"
示例 2:
输入:s = ")()())" 输出:4 解释:最长有效括号子串是 "()()"
示例 3:
输入:s = "" 输出:0
提示:
0 <= s.length <= 3 * 104
s[i]
为'('
或')'
解答:
可以通过使用栈和动态规划两种方法来解决。
方法一:使用栈
利用栈来解决括号匹配的问题,具体步骤如下:
-
使用栈保存括号索引:
- 遍历字符串,遇到 '(' 将其索引入栈。
- 遇到 ')' 时,如果栈不空且栈顶为 '(',说明找到了一对有效括号,可以计算当前有效括号的长度并更新最大长度。
- 如果栈顶为 ')' 或者栈为空,则将当前 ')' 的索引入栈,作为之后可能有效括号的起始点。
-
遍历完成后计算最长有效长度:
- 如果栈为空,说明整个字符串是有效的括号,长度为字符串长度。
- 否则,栈中剩下的元素表示无法匹配的括号位置,通过这些位置计算最长有效括号的长度。
#include <stack> #include <string> #include <algorithm> using namespace std; class Solution { public: int longestValidParentheses(string s) { int maxLen = 0; stack<int> stk; stk.push(-1); // 先放入一个哨兵,用于计算有效长度 for (int i = 0; i < s.length(); ++i) { if (s[i] == '(') { stk.push(i); } else { // s[i] == ')' stk.pop(); if (stk.empty()) { stk.push(i); // 更新新的哨兵 } else { maxLen = max(maxLen, i - stk.top()); } } } return maxLen; } };
方法二:使用动态规划
动态规划的思路是定义一个
dp
数组,其中dp[i]
表示以s[i]
结尾的最长有效括号子串的长度。具体步骤如下: -
初始化:将
dp
数组全部初始化为 0。 -
状态转移:
- 如果
s[i]
为 '(',dp[i]
必然为 0,因为不可能以 '(' 结尾形成有效括号。 - 如果
s[i]
为 ')',需要判断前一个字符s[i-1]
:- 如果
s[i-1]
为 '(',则dp[i] = dp[i-2] + 2
,即前一个有效括号子串的长度加上当前括号对的长度。 - 如果
s[i-1]
为 ')' 并且i-dp[i-1]-1 >= 0
且s[i-dp[i-1]-1] == '('
,则dp[i] = dp[i-1] + 2 + dp[i-dp[i-1]-2]
。
- 如果
- 如果
-
计算最大长度:遍历
dp
数组找出最大值作为结果。class Solution { public: int longestValidParentheses(string s) { int maxLen = 0; // 初始化最大有效括号长度为0。 int n = s.length(); // 获取输入字符串的长度。 vector<int> dp(n, 0); // 创建一个长度为n的数组dp,用于存储以每个位置结尾的最长有效括号长度。 for (int i = 1; i < n; ++i) { // 从第二个字符开始遍历输入字符串。 if (s[i] == ')') { // 如果当前字符是右括号: if (s[i - 1] == '(') { // 如果前一个字符是左括号: dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; // 更新dp[i]为前一个位置的有效括号长度加2。 } else if (i - dp[i - 1] > 0 && s[i - dp[i - 1] - 1] == '(') { // 如果前一个字符是右括号,并且前一个有效括号的起始位置在当前位置之前,并且前一个有效括号的前一个字符是左括号: dp[i] = dp[i - 1] + (i - dp[i - 1] >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; // 更新dp[i]为前一个有效括号的长度加上前一个有效括号之前的有效括号长度(如果有的话)再加2。 } maxLen = max(maxLen, dp[i]); // 更新最大有效括号长度。 } } return maxLen; // 返回最终的最大有效括号长度。 } };