LeetCode0032. 最长有效括号

一. 题目
  1. 题目
    给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。
  2. 示例
    在这里插入图片描述
二. 方法一: 暴力
  1. 解题思路
    判断每一个子串是否是合法的, 然后返回最长合法子串的长度
    python 运行会超时

  2. 解题代码

    def isValid(self, s:str):
        list1 = []
        for ele in s:
            if ele == '(':
                list1.append(ele)
            elif list1 and list1[-1] == '(':
                list1.pop()
            else:
                return False
        return True if not list1 else False
    
    def longestValidParentheses(self, s: str) -> int:
        size = len(s)
        max_len = 0
        for i in range(0, size):
            for j in range(i + 1, size +1):
                if self.isValid(s[i: j]):
                    if max_len < j - i:
                        max_len = j - i
        return max_len
    
  3. 分析:
    时间复杂度: O(n^3)
    空间复杂度: O(n)

三. 方法二: 栈
  1. 解题思路

    之前是将"(“括号放入列表, 遇到”)“就弹出, 每弹出一次就将长度+2, 如果遇到括号不匹配, 则将当前的长度修改为0,
    然后继续判断后续的括号 存在的问题: 如果存在多余的”(", 不能判断出来, 如"()(()"

    1. 将"("的下标存入到列表中,
    2. 如果遇到")", 则弹出末尾的元素
    3. 如果弹出元素后, 列表为空, 则将当前的下标存入到列表
    4. 如果弹出后不为空, 则获取当前最长括号的有效长度: 当前索引 - 末尾最后一个元素的值
    5. 返回最大值
  2. 解题代码

    • 错解

      def longestValidParentheses(s: str) -> int:
          max1 = 0
          len1 = 0
          list1 = []
          for ele in s:
              if ele == '(':
                  list1.append(ele)
              elif list1 and ele == ')' and list1[-1] == '(':
                  list1.pop()
                  len1 += 2
                  if max1 < len1:
                      max1 = len1
              else:
                  len1 = 0
      
          return max1
      
    • 正解:

      def longestValidParentheses(self, s: str) -> int:
          max1 = 0
          list1 = [-1]
          for i in range(len(s)):
          	# 如果当前元素是"(", 则将下标索引存入到列表末尾
              if s[i] == '(':
                  list1.append(i)
              else: 
              	# 如果当前元素是")", 则将列表最后一个元素弹出
                  list1.pop()
                  # 如果此时列表为空, 则存放当前元素的下标到列表中
                  if not list1:
                      list1.append(i)
                  else:
                  	# 获取列表中最后一个元素的值
                  	# 即: 当前合格符号的起始下标
                      ite = list1[-1]
                      # i - list1[-1] 表示当前合格符号的长度
                      max1 = max(max1, i - list1[-1])
          return max1
      
  3. 分析:
    时间复杂度: O(n)
    空间复杂度: O(n)

四. 方法三: 动态规划
  1. 解题思路

  2. 解题代码

    def longestValidParentheses(s: str) -> int:
        size = len(s)
        # 创建一个数组
        # list1[i]表示以下标为i的字符为结尾的最长有效括号的子串的长度
        list1 = [0 for _ in range(size)]
        max_len = 0
        for i in range(1, size):
            # 如果当前位置是")"
            if s[i] == ')':
                # 如果前一个位置是"(", 此时刚好可以组合成"()"
                # "XXX?()"
                if s[i - 1] == '(':
                    # 如果 i < 2, 则此时直接赋值为2, 相当于字符串以"()"开头
                    list1[i] = 2
                    # 如果 i >= 2, 则此时直接在原有值的基础上加2
                    if i - 2 >= 0:
                        list1[i] = list1[i - 2] + 2
                # 如果当前位置的前一个元素也是")"
                # "?((...))"
                elif list1[i - 1] > 0:
                    # 获取到list1中起一个元素的最长合法符号的起始下标
                    # 当前下标 - 前一个元素最长合法符号的长度
                    pre = i - list1[i - 1]
                    # 如果前一个元素还是为"(", 相当于将之前的子串用"(" 和 ")"包起来了
                    if pre - 1 >= 0 and s[pre - 1] == '(':
                        # 在原有的长度基础上 + 2
                        list1[i] = list1[i - 1] + 2
                        # 如果拼接后之前的长度还是 >= 2
                        # "(...)((...))"
                        if pre - 2 >= 0:
                            # 则在现有的基础上 还要加上之前的最长合法符号的长度
                            list1[i] += list1[pre - 2]
            max_len = max(max_len, list1[i])
        return max_len
    
  3. 分析
    时间复杂度: O(n)
    空间复杂度: O(n)

五. 方法四: 不需额外的空间
  1. 解题思路

    1. 两个计数器 leftft 和 right
    2. 首先,我们从左到右遍历字符串,
    3. 对于遇到的每个 ‘(’,我们增加 left计算器; 对于遇到的每个 ‘)’ ,我们增加 right 计数器。
    4. 每当 left 计数器与 right 计数器相等时,我们计算当前有效字符串的长度,并且记录目前为止找到的最长子字符串。
    5. 如果 right 计数器比 left 计数器大时,我们将 left 和 right 计数器同时变回 0 。
    6. 对于遇到的每个 ‘(’,我们增加 left计算器; 对于遇到的每个 ‘)’ ,我们增加 right 计数器。
    7. 然后,我们从右到左遍历字符串,
    8. 每当 left 计数器与 right 计数器相等时,我们计算当前有效字符串的长度,并且记录目前为止找到的最长子字符串。
    9. 如果 left 计数器比 right 计数器大时,我们将 left 和 right 计数器同时变回 0 。
    10. 返回最长长度即可
  2. 解题代码

    def longestValidParentheses(self, s: str) -> int:
        size = len(s)
        left, right = 0, 0
        max_len = 0
        # 第一轮循环: 从左到右
        for i in range(size):
            if s[i] == '(':
                left += 1
            if s[i] == ')':
                right += 1
            if left == right:
            	# 计算当前有效字符串的长度
                len1 = 2 * left
                max_len = max(max_len, len1)
            # ")" 比 "("多
            if left < right:
                left, right = 0, 0
        left, right = 0, 0
        # 第二轮循环: 从右到左
        for i in range(size - 1, -1, -1):
            if s[i] == '(':
                left += 1
            if s[i] == ')':
                right += 1
            if left == right:
            	# 计算当前有效字符串的长度
                len1 = 2 * left
                max_len = max(max_len, len1)
            # "(" 比 ")"多
            if left > right:
                left, right = 0, 0
        return max_len
    
  3. 分析
    时间复杂度: O(n)
    空间复杂度: O(1), 就创建了几个变量

六. 方法五: 状态标记
  1. 解题思路
    此法是之前栈方法的一种变形, 是在评论区看到的一种解法, 我认为对开拓思维有一定的帮助, 故放在此处.

  2. 解题放啊

    def longestValidParentheses(s: str) -> int:
        size = len(s)
        # 存放所有"("的下标
        list1 = []
        max_len = 0
        len1 = 0
        # 标记出无法匹配的括号
        mark = [0 for _ in range(size)]
        for i in range(size):
            if s[i] == '(':
                list1.append(i)
            else:
                # 如果此时列表为空, 则")"无法匹配, 所以标记为1
                if not list1:
                    mark[i] = 1
                else: # 否则, 弹出与之相匹配的"("
                    list1.pop()
        # 此时list1中存放的元素, 即为未匹配的多余的"(", 标记为1
        while list1:
            mark[list1[-1]] = 1
            list1.pop()
        # 然后遍历mark获取所有的状态, 最长的连续0的长度即为最长有效括号的长度
        for i in range(size):
            # 如果遇到了不匹配的括号, 直接修改当前长度为0
            if mark[i]:
                len1 = 0
                continue
            len1 += 1
            max_len = max(max_len, len1)
        return max_len
    
  3. 分析
    时间复杂度: O(n)
    空间复杂度: O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值