给定一个只包含 '('
和 ')'
的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
示例 2:
输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"
解题思路
这种问题我们首先想到的解决思路是通过栈。我们首先遍历一遍s
,判断遍历到的字符ch
是不是(
,如果是的话,我们就将ch.index
加入到栈中,例如
( ( )
↑
stack: 0
如果遍历到的元素是)
,且栈不为空栈顶元素是(
,我们就出栈。
( ( )
↑
stack: 0
否则如果栈为空,我们就将ch.index
入栈。这样扫面完一轮,我们的栈里面存放的就是没有匹配到的位置。例如
stack: | 0 3 7 13 |
-1 len(s)
此时我们只要遍历stack
,找到两两元素之间隔最大的距离即可。
class Solution:
def longestValidParentheses(self, s):
"""
:type s: str
:rtype: int
"""
s_len, stack = len(s), list()
for i, ch in enumerate(s):
if ch == '(':
stack.append(i)
elif stack and s[stack[-1]] == '(':
stack.pop()
else:
stack.append(i)
if not stack:
return s_len
stack = [-1] + stack + [s_len]
for i,val in enumerate(stack[1:]):
stack[i] = val - stack[i] - 1
return max(stack[:-1])
这个问题也可以通过动态规划来做,而且思路也非常清晰。我们定义
表示当前位置i
结尾的最长有效括号的长度,那么
稍微说明一下,因为
为此时的最大长度,那么i-1-f(i)
就表示之前还未匹配的(
,例如
( ) ( ( ) )
↑ i
如果我们的i
在这个位置,那么i-1-f(i)
就是箭头所指的位置。由于此时箭头所指的位置是(
,所以我们应该将f(i)+2=4
。但是我们此时得到只是一个小区间内的最大值,我们应该还要加上以箭头前一位置结尾的最大长度,那么此时我们得到的解过就是以i
结尾的最大长度。
最后这个算法还有一个小问题,如果我们此时i
是(
怎么办?我们上面的f(i)+2
就是错误的。所以我们干脆不考虑这种情况,只考虑)
即可。那么只考虑)
情况是合理的吗?合理,因为最长有效括号一定是以)
结尾。
class Solution:
def longestValidParentheses(self, s):
"""
:type s: str
:rtype: int
"""
s_len, result = len(s), 0
if s_len < 2:
return 0
mem = [0]*s_len
for i in range(1, s_len):
if s[i] == ')':
left = i-1-mem[i-1]
if left >= 0 and s[left] == '(':
mem[i] = mem[i-1] + 2
mem[i] += mem[i-mem[i]]
result = max(result, mem[i])
return result
reference:
https://leetcode.com/problems/longest-valid-parentheses/discuss/14126/My-O(n)-solution-using-a-stack
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!