diff --git a/README.md b/README.md index 0295d87..b245b5f 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ My LeetCode solutions with Chinese explanation. 我的LeetCode中文题解。 | 28 |[Implement strStr()](https://leetcode.com/problems/implement-strstr/)|[C++](solutions/28.%20Implement%20strStr().md)|Easy| | | 29 |[Divide Two Integers](https://leetcode.com/problems/divide-two-integers)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/29.%20Divide%20Two%20Integers.md)|Medium| | | 31 |[Next Permutation](https://leetcode.com/problems/next-permutation)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/31.%20Next%20Permutation.md)|Medium| | +| 32 |[Longest Valid Parentheses](https://leetcode.com/problems/longest-valid-parentheses/)|[C++](solutions/32.%20Longest%20Valid%20Parentheses.md)|Hard| | | 34 |[Find First and Last Position of Element in Sorted ](https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/34.%20Find%20First%20and%20Last%20Position%20of%20Element%20in%20Sorted%20Array.md)|Medium| | | 33 |[Search in Rotated Sorted Array](https://leetcode.com/problems/search-in-rotated-sorted-array/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/33.%20Search%20in%20Rotated%20Sorted%20Array.md)|Medium| | | 35 |[Search Insert Position](https://leetcode.com/problems/search-insert-position)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/35.%20Search%20Insert%20Position.md)|Easy| | diff --git a/solutions/32. Longest Valid Parentheses.md b/solutions/32. Longest Valid Parentheses.md new file mode 100644 index 0000000..3cbed60 --- /dev/null +++ b/solutions/32. Longest Valid Parentheses.md @@ -0,0 +1,110 @@ +# [32. Longest Valid Parentheses](https://leetcode.com/problems/longest-valid-parentheses/) + +# 思路 + +求有效括号匹配子串的最大长度。 + +## 思路一、栈 + +括号匹配类的问题往往都能用栈解决,此题也不例外。 + +从前往后遍历字符串,设下标为i +* 如果遇到左括号或者栈空,则将当前下标i压入栈; +* 如果遇到右括号且栈顶为左括号,则遇到了匹配的括号对,将栈顶弹出即可; + +然后就可以计算以字符`s[i]`作为结尾的最大长度:`i - stk.top()`。 + +时空复杂度均为O(n) + +## 思路二、动归 + +由于此问题存在很多子问题,且子问题之前又有很多重复,所可以考虑用动归。 + +先来看状态定义: +``` +dp[i]: 以字符s[i]结尾的最大匹配长度 +``` +状态转移方程就很简单了: +* 如果`s[i] = '('`,那么`dp[i] = 0`; +* 否则,我们需要看以字符`s[i-1]`为结尾的最大匹配子串的前面那个字符`s[i - dp[i-1] - 1]`是否是左括号: + * 若是,说明匹配上了,所以`dp[i] = dp[i-1] + 2 + dp[i - dp[i-1] - 2]`; + * 若不是,则没匹配上,`dp[i] = 0`。 + +时空复杂度均为O(n) + +## 思路三 + +前面两种思路的空间复杂度均为O(n),此题还有一种常数空间的思路,和前面栈的思想有点类似。 + +使用两个变量left和right分别用来记录到当前位置时左括号和右括号的出现次数,当遇到左括号时,left自增1;否则right自增1。 + +* 当`left == right`时,说明匹配成功,此时匹配长度为`2*left`; +* 一旦遇到`right > left`,说明当前位置不能匹配,则重新开始,即left和right均重置为0。 + +但是对于"(()"这种时,在遍历结束时左右子括号数都不相等,此时没法更新结果res,但其实正确答案是2,怎么处理这种情况呢?答案是再反向遍历一遍,采取类似的方法,稍有不同的是此时若`right < left`了,则重置0。 + +时间复杂度O(n),空间复杂度O(1) + +# C++ + +## 思路一 +``` C++ +class Solution { +public: + int longestValidParentheses(string s) { + stackstk; + int res = 0, start = 0; + for(int i = 0; i < s.size(); i++){ + if(!stk.empty() && s[stk.top()] == '(' && s[i] == ')') stk.pop(); + else stk.push(i); + // 栈顶为当前匹配子串的起始位置 + res = max(res, stk.empty() ? i + 1 : i - stk.top()); + } + return res; + } +}; +``` + +## 思路二 +``` C++ +class Solution { +public: + int longestValidParentheses(string s) { + vectordp(s.size(), 0); + int res = 0; + for(int i = 1; i < s.size(); i++){ + if(s[i] == '(') continue; + int tmp = i - dp[i-1] - 1; + if(tmp >= 0 && s[tmp] == '(') + dp[i] = dp[i-1] + 2 + (tmp >= 1 ? dp[tmp - 1] : 0); + res = max(res, dp[i]); + } + return res; + } +}; +``` + +## 思路三 +``` C++ +class Solution { +public: + int longestValidParentheses(string s) { + int res = 0, left = 0, right = 0, n = s.size(); + for (int i = 0; i < n; i++) { + if(s[i] == '(') left++; + else 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--) { + if(s[i] == '(') left++; + else right++; + if (left == right) res = max(res, 2 * left); + else if (left > right) left = right = 0; + } + return res; + } +}; +``` \ No newline at end of file