概述
[LeetCode] 32. Longest Valid Parentheses 最长有效括号
Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring.
Example 1:
Input: "(()"
Output: 2
Explanation: The longest valid parentheses substring is "()"
Example 2:
Input: ")()())"
Output: 4
Explanation: The longest valid parentheses substring is "()()"
这道求最长有效括号比之前那道 Valid Parentheses 难度要大一些,这里还是借助栈来求解,需要定义个 start 变量来记录合法括号串的起始位置,遍历字符串,如果遇到左括号,则将当前下标压入栈,如果遇到右括号,如果当前栈为空,则将下一个坐标位置记录到 start,如果栈不为空,则将栈顶元素取出,此时若栈为空,则更新结果和 i - start + 1 中的较大值,否则更新结果和 i - st.top() 中的较大值,参见代码如下:
解法一:
class Solution { public: int longestValidParentheses(string s) { int res = 0, start = 0, n = s.size(); stack<int> st; for (int i = 0; i < n; ++i) { if (s[i] == '(') st.push(i); else if (s[i] == ')') { if (st.empty()) start = i + 1; else { st.pop(); res = st.empty() ? max(res, i - start + 1) : max(res, i - st.top()); } } } return res; } };
还有一种利用动态规划 Dynamic Programming 的解法。这里使用一个一维 dp 数组,其中 dp[i] 表示以 s[i-1] 结尾的最长有效括号长度(注意这里没有对应 s[i],是为了避免取 dp[i-1] 时越界从而让 dp 数组的长度加了1),s[i-1] 此时必须是有效括号的一部分,那么只要 dp[i] 为正数的话,说明 s[i-1] 一定是右括号,因为有效括号必须是闭合的。当括号有重合时,比如 "(())",会出现多个右括号相连,此时更新最外边的右括号的 dp[i] 时是需要前一个右括号的值 dp[i-1],因为假如 dp[i-1] 为正数,说明此位置往前 dp[i-1] 个字符组成的子串都是合法的子串,需要再看前面一个位置,假如是左括号,说明在 dp[i-1] 的基础上又增加了一个合法的括号,所以长度加上2。但此时还可能出现的情况是,前面的左括号前面还有合法括号,比如 "()(())",此时更新最后面的右括号的时候,知道第二个右括号的 dp 值是2,那么最后一个右括号的 dp 值不仅是第二个括号的 dp 值再加2,还可以连到第一个右括号的 dp 值,整个最长的有效括号长度是6。所以在更新当前右括号的 dp 值时,首先要计算出第一个右括号的位置,通过 i-3-dp[i-1] 来获得,由于这里定义的 dp[i] 对应的是字符 s[i-1],所以需要再加1,变成 j = i-2-dp[i-1],这样若当前字符 s[i-1] 是左括号,或者j小于0(说明没有对应的左括号),或者 s[j] 是右括号,此时将 dp[i] 重置为0,否则就用 dp[i-1] + 2 + dp[j] 来更新 dp[i]。这里由于进行了 padding,可能对应关系会比较晕,大家可以自行带个例子一步一步执行,应该是不难理解的,参见代码如下:
解法二:
class Solution { public: int longestValidParentheses(string s) { int res = 0, n = s.size(); vector<int> dp(n + 1); for (int i = 1; i <= n; ++i) { int j = i - 2 - dp[i - 1]; if (s[i - 1] == '(' || j < 0 || s[j] == ')') { dp[i] = 0; } else { dp[i] = dp[i - 1] + 2 + dp[j]; res = max(res, dp[i]); } } return res; } };
此题还有一种不用额外空间的解法,使用了两个变量 left 和 right,分别用来记录到当前位置时左括号和右括号的出现次数,当遇到左括号时,left 自增1,右括号时 right 自增1。对于最长有效的括号的子串,一定是左括号等于右括号的情况,此时就可以更新结果 res 了,一旦右括号数量超过左括号数量了,说明当前位置不能组成合法括号子串,left 和 right 重置为0。但是对于这种情况 "(()" 时,在遍历结束时左右子括号数都不相等,此时没法更新结果 res,但其实正确答案是2,怎么处理这种情况呢?答案是再反向遍历一遍,采取类似的机制,稍有不同的是此时若 left 大于 right 了,则重置0,这样就可以 cover 所有的情况了,参见代码如下:
解法三:
class Solution { public: int longestValidParentheses(string s) { int res = 0, left = 0, right = 0, n = s.size(); for (int i = 0; i < n; ++i) { (s[i] == '(') ? ++left : ++right; if (left == right) res = max(res, 2 * right); else if (right > left) left = right = 0; } left = right = 0; for (int i = n - 1; i >= 0; --i) { (s[i] == '(') ? ++left : ++right; if (left == right) res = max(res, 2 * left); else if (left > right) left = right = 0; } return res; } };
到此这篇关于C++实现LeetCode(32.最长有效括号)的文章就介绍到这了,更多相关C++实现最长有效括号内容请搜索靠谱客以前的文章或继续浏览下面的相关文章希望大家以后多多支持靠谱客!
最后
以上就是笑点低龙猫为你收集整理的C++实现LeetCode(32.最长有效括号)的全部内容,希望文章能够帮你解决C++实现LeetCode(32.最长有效括号)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复