Longest Valid Parentheses
Description
Given a string containing just the characters ‘(‘ and ‘)’, find the length of the longest valid (well-formed) parentheses substring.
Example
Example 1:
Input: “(()”
Output: 2
Explanation: The longest valid parentheses substring is “()”Example 2:
Input: “)()())”
Output: 4
Explanation: The longest valid parentheses substring is “()()”
Analysis
题目意思为,给定一个只包含左括号 ‘(‘ 和右括号 ‘)’的字符串,找出其中最长的合法括号字串,即该字串满足左右括号匹配原则。
如果这是一道简单的括号匹配题,那么非常简单,是一道栈的使用练习题:左括号入栈,右括号匹配栈顶元素,成功则出栈,失败则不合法;最栈非空也为不合法。
这个合法匹配问题,给出了一部分的解题思路。因为在合法的字符串中,左括号与右括号的匹配是一一对应的,即无法对应其他括号。这也是可以利用栈来操作的基础。那么我们就可以写出一个 $O(2n)$ 的解法了:
- 通过栈操作,将所有匹配括号打上 tag
- 扫描 tag,得到最长的 tag 串
Accept Picture
Code
1 | int longestValidParentheses(string str) { |
Further Thinking
这道题是否可以利用 DP 来做呢?是可以的。
我们定义 l[m] 为以 str[m] 结尾的最长合法字串的长度。
那么对于任意一个 l[i] (0 < i < n),我们可以计算它的值:
- str[i] 是 ‘(‘,那么 l[i] = 0,因为不存在以 ‘(‘ 结尾的合法串
- str[i] 是 ‘)’,那么需要考察前一个括号
- 如果 str[i-1] 是 ‘(‘,那么 str[i-1] 和 str[i] 是匹配的,因为括号匹配规则中不存在跨越最近匹配的情况,那么 l[i] = l[i-2] + 2
- 如果 str[i-1] 是 ‘)’,那么需要考察与 str[i-1] 匹配的最长串前的符号 str[i-1-l[i-1]],由此确定 str[i] 是否可以加入这个串。
- 如果 str[i-1-l[i-1]] 是 ‘(‘,那么 str[i] 与 str[i-1-l[i-1]]是匹配的,即
( str[i-1-l[i-1]+1]...str[i-1] )
,其中str[i-1-l[i-1]...str[i-1]
是合法串,整个串也是合法的,那么 l[i] = l[i-1] + 2。但是,还不够详细,因为在这个串前的串可能是合法的,即previousString ( str[i-1-l[i-1]+1]...str[i-1] )
中的 previousString 可以是合法的。所以 l[i] = l[i-1] +2 + l[i-2-l[i-1]] - 如果 str[i-1-l[i-1]] 是 ‘)’,那么 str[i-1-l[i-1]] 与 str[i] 无法匹配,l[i] = 0
- 如果 str[i-1-l[i-1]] 是 ‘(‘,那么 str[i] 与 str[i-1-l[i-1]]是匹配的,即
这样,就把 l[i] 的计算公式给全了,也就是我们的 DP 式。其中,l[0] 一定是0,因为单独无法成为合法串,所以计算 n-1 次即可。伪代码如下,算法复杂度为 $O(n)$:
1 | # Index validation is not contained in the pseudocode |
AC 截图如下:
代码如下:
1 | int longestValidParentheses(string str) { |