LeetCode题练习与总结:最长有效括号

118 篇文章 0 订阅
20 篇文章 0 订阅

一、题目描述

给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号

子串

的长度。

示例 1:

输入:s = "(()"
输出:2
解释:最长有效括号子串是 "()"

示例 2:

输入:s = ")()())"
输出:4
解释:最长有效括号子串是 "()()"

示例 3:

输入:s = ""
输出:0

提示:

  • 0 <= s.length <= 3 * 10^4
  • s[i]'('')'

二、解题思路

1. 初始化一个栈和一个变量 maxLen 来记录最长有效括号子串的长度。栈用于存储左括号的索引,maxLen 初始化为 0。

2. 遍历字符串 s 中的每个字符。对于每个字符,执行以下操作:

(1)如果当前字符是左括号 '(',则将其索引压入栈中。

(2)如果当前字符是右括号 ')',则执行以下步骤:

  • 如果栈不为空,并且栈顶元素是左括号索引,说明找到了一个匹配的括号对。此时,弹出栈顶元素(左括号索引),并计算当前右括号索引与栈顶左括号索引之间的距离(即有效括号子串的长度)。
  • 更新 maxLen 为当前 maxLen 和刚刚计算的有效括号子串长度的最大值。
  • 如果栈为空,说明当前的右括号没有匹配的左括号,将当前索引作为新的左括号压入栈。

3. 遍历结束后,返回 maxLen 作为最长有效括号子串的长度。

这个思路的核心在于利用栈来跟踪左括号的位置,并通过栈顶元素与当前右括号索引之间的距离来确定有效括号子串的长度。这种方法不需要额外的动态规划数组,只需要一个栈和一些基本的索引操作。

三、具体代码

class Solution {
    public int longestValidParentheses(String s) {
        int maxLen = 0;
        int n = s.length();
        if (n == 0) return 0;

        Stack<Integer> stack = new Stack<>();
        stack.push(-1); // 初始化栈,-1 表示没有匹配的左括号

        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == '(') {
                stack.push(i); // 遇到左括号,压入栈
            } else {
                // 遇到右括号
                stack.pop(); // 弹出栈顶元素,即左括号的索引
                if (stack.isEmpty()) {
                    // 如果栈为空,说明当前右括号没有匹配的左括号
                    stack.push(i); // 将当前索引作为新的左括号压入栈
                } else {
                    // 如果栈不为空,计算当前有效括号的长度
                    int leftIndex = stack.peek();
                    maxLen = Math.max(maxLen, i - leftIndex);
                }
            }
        }

        return maxLen;
    }
}

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 时间复杂度:O(n)。
  • 代码中有两个循环。
  • 外层循环遍历字符串的每个字符,内层循环(实际上是一个条件判断)在遇到右括号时可能会执行。
  • 在最坏的情况下,每个字符都会导致内层循环执行,因此时间复杂度是 O(n),其中 n 是字符串的长度。
2. 空间复杂度
  • 空间复杂度:O(n)。
  • 栈的大小取决于字符串中左括号和右括号的分布。
  • 在最坏的情况下,如果字符串中的所有括号都是成对出现的,那么栈的大小将等于字符串的长度。
  • 因此,空间复杂度是 O(n)。

五、总结知识点

  1. 栈(Stack):栈是一种后进先出(LIFO)的数据结构,它用于存储和管理数据。在这个问题中,栈用于跟踪左括号的索引,以便在遇到右括号时能够找到匹配的左括号。

  2. 字符串遍历:代码通过一个 for 循环遍历字符串的每个字符。这是处理字符串问题时常见的方法。

  3. 条件判断:在遍历过程中,代码使用 ifelse 语句来判断当前字符是左括号还是右括号,并根据条件执行不同的操作。

  4. 栈操作:代码中使用了栈的基本操作,包括 push(压入元素)和 pop(弹出元素)。push 用于将左括号的索引添加到栈中,而 pop 用于在找到匹配的右括号时移除左括号的索引。

  5. 变量更新:在遍历过程中,代码不断更新 maxLen 变量,以记录到目前为止找到的最长有效括号子串的长度。

  6. 边界条件处理:代码在开始时检查字符串长度是否为 0,如果是,则直接返回 0,因为空字符串没有有效的括号子串。

  7. 初始化:栈被初始化为包含一个特殊的值 -1,这个值表示没有匹配的左括号。这是一种常见的技巧,用于简化边界条件的处理。

  8. 数学运算:代码中使用了 Math.max 方法来获取两个整数的最大值,这是在更新最长有效括号子串长度时需要的操作。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一直学习永不止步

谢谢您的鼓励,我会再接再厉的!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值