时间复杂度:O(n) 其中 n 为字符串的长度。 遍历整个字符串一次,求出 dp 数组。 空间复杂度:O(n) */ classSolution_1 { public: intlongestValidParentheses(string s){ int n = s.size(); vector<int> f(n, 0); // 初始化为 0 int res = 0; // 最长有效括号子串的长度
for (int i = 1; i < n; i++) { if (s[i] == ')') { // 右括号才可能构成有效括号对 if (s[i-1] == '(') { // 前一个是 '(',直接构成 "()" f[i] = (i >= 2 ? f[i-2] : 0) + 2; } elseif (i-f[i-1] > 0 && s[i-f[i-1]-1] == '(') { // 前一个是 ')', 形成嵌套括号结构 f[i] = f[i-1] + 2; if (i-f[i-1]-2 >= 0) { f[i] += f[i-f[i-1]-2]; // 加上前一个有效子串 } } res = max(res, f[i]); // 更新最大值 } }
return res; } };
/* 两次线性扫描,贪心地考虑以当前下标结尾的有效括号长度。
两个计数器 left 和 right,从左向右遍历字符串。 left 等于 right 时,计算当前有效字符串的长度,并记录当前找到的最长子字符串; left 小于 right 时,将 left 和 right 计数器同时变回 0。 右括号数量多于左括号数量时,之前的字符不再考虑,重新从下一个字符开始计算, 但这样会漏掉一种情况,左括号的数量大于右括号的数量,即 (() ,这时最长有效括号无法求出。 解决方法: 从右向左遍历的方法计算,判断条件反过来: left 等于 right 时,计算当前有效字符串的长度,并记录当前找到的最长子字符串; left 大于 right 时,将 left 和 right 计数器同时变回 0。
时间复杂度:O(n) 遍历两次字符串。 空间复杂度:O(1) */ classSolution { public: intlongestValidParentheses(string s){ int res = 0; int left = 0, right = 0;
// 从左向右遍历 for (int i = 0; i < s.size(); i++) { if (s[i] == '(') { left++; } elseif (s[i] == ')') { right++; }
if (left == right) { res = max(res, right*2); } elseif (left < right) { left = right = 0; } }
left = right = 0; // 从右向左遍历 for (int i = s.size()-1; i >= 0; i--) { if (s[i] == '(') { left++; } elseif (s[i] == ')') { right++; }
if (left == right) { res = max(res, left*2); } elseif (left > right) { left = right = 0; } }