主要参考资料:
LeetCode-32.最长有效括号(考察点:栈/动态规划)
https://blog.csdn.net/weixin_38823568/article/details/80997966
leetcode本身的solution
https://leetcode.com/problems/longest-valid-parentheses/solution/#
方法一:暴力解法
主要思想:对所有位置进行两两组合,然后对组合后得到的字符串进行有效性检验(leetcode有对应的题),维护一个maximum变量,存储最长的有效字符串长度。
时间复杂度:O(n**3)
空间复杂度:O(n)(最长的子集)
代码:略
方法二:使用动态规划
主要思想:是从左向右扫描字符串,维护一个长度和字符串一样的数组dp,记录以对应位置结尾的最长有效括号子集的长度。
考虑动态规划,当我们进行到n位置的时候,可能会遇到两种情况
A:string[n]=”(“,已知有效字符串不可能是左括号结尾,所以dp[n]为0
B:string[n]=”)“,这时又会有两种情况:
- string[n-1]=”(“,这时正好构成一个有效的子字符串,考虑到可能情况是连续的有效子集,所以需要再加上dp[n-2]。
- string[n-1]=”)”,根据dp[n-1]的信息我们可以知道前面有效子集的长度,然后检验这个有效子集的开始的前面一位是否是“(”,如果不是的话,以该位置为结尾的有效字符串长度就是0,如果是的话,有效字符串长度就是dp[n-1]+2+考虑连续有效子集的情况
时间复杂度:O(n)
空间复杂度:O(n)
class Solution:
def longestValidParentheses(self, s):
if s=="": return 0
dp=[0]*len(s)
for i in range(len(s)):
if s[i]==")":
if i-1>=0 and s[i-1]=="(":
if i-2>=0:
dp[i]=dp[i-2]+2
else:
dp[i]=2
elif i-1>=0 and s[i-1]==")":
if i-dp[i-1]-1>=0 and s[i-dp[i-1]-1]=="(":
if i-dp[i-1]-2>=0:
dp[i]=dp[i-dp[i-1]-2]+dp[i-1]+2
else:
dp[i]=dp[i-1]+2
return max(dp)
方法三:使用栈
主要思想:基于判断括号有效子集的方法扩展,主要思想是扫描字符串,遇到“(”的时候,将对应的index存储在stack中,遇到“)”的时候,意味着可能遇到了一个有效子字符串,所以需要维护一个maximam变量。
计算maximum的方法是,存一个start变量,是我们认为的有效的子集开始的位置,然后遍历字符串,利用不同的位置减去start得到的值,来维护maximum。
时间复杂度:O(n)
空间复杂度:O(n)
class Solution:
def longestValidParentheses(self, s):
start=0
maximum=0
stack=[]
for i in range(len(s)):
if s[i]=='(':
stack.append(i)
else:
if stack==[]:
start=i+1
else:
stack.pop()
if stack!=[]:
maximum=max(maximum,i-stack[-1])
else:
maximum=max(maximum,i-start+1)
return maximum
方法四:双变量方法
遍历两边字符串,用两个变量存储左括号和右括号的数量,当两者相等的时候,变量*2就是一个可能的最大值。
class Solution:
def longestValidParentheses(self, s):
left=0
right=0
maximum=0
for i in s:
if i=="(":
left+=1
else:
right+=1
if left==right:
maximum=max(maximum,2*left)
elif right>left:
left=0
right=0
left=0
right=0
for i in s[::-1]:
if i=="(":
left+=1
else:
right+=1
if left==right:
maximum=max(maximum,2*left)
elif right<left:
left=0
right=0
return maximum