leetcode
leetcode 1 ~ 50
最长有效括号

最长有效括号

难度:

标签:

题目描述

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

 

示例 1:

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

示例 2:

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

示例 3:

输入:s = ""
输出:0

 

提示:

  • 0 <= s.length <= 3 * 104
  • s[i]'('')'

代码结果

运行时间: 28 ms, 内存: 15 MB


/*
 * 思路:
 * 使用堆栈来跟踪未匹配的'('的索引。初始状态下,push -1到堆栈中作为基础。
 * 遍历字符串s,如果是'(',将索引推入堆栈。
 * 如果是')',从堆栈中弹出。若堆栈为空,推入当前索引,否则计算当前有效括号长度。
 */
import java.util.Stack;
 
public class Solution {
    public int longestValidParentheses(String s) {
        Stack<Integer> stack = new Stack<>();
        stack.push(-1);
        int maxLen = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                stack.push(i);
            } else {
                stack.pop();
                if (stack.isEmpty()) {
                    stack.push(i);
                } else {
                    maxLen = Math.max(maxLen, i - stack.peek());
                }
            }
        }
        return maxLen;
    }
}

解释

方法:

该题解使用栈来解决问题。遍历字符串,遇到左括号就将其索引入栈,遇到右括号则将栈顶元素出栈,并更新最长有效括号子串的长度。如果栈为空,则将当前索引 i 赋值给 j,表示上一个最长有效括号子串的结束位置。最后返回最长有效括号子串的长度。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在遇到右括号且栈为空时,需要将当前索引赋值给变量j,这样做有什么作用?
在遇到右括号且栈为空的情况通常表示当前右括号没有对应的左括号与之匹配,因此这个右括号是无效的。将当前索引赋值给变量j,是为了更新后续有效括号子串的起始位置。此时,j表示最后一个无法被匹配的右括号的位置。这样,后续遇到有效的括号对时,可以正确地计算其长度,即从最后一个无效右括号后的位置开始计算。
🦆
如果栈中有剩余的左括号索引未被匹配,那么这些情况如何影响最长有效括号子串的计算?
如果栈中剩余了左括号的索引,这表示这些左括号没有对应的右括号与之匹配。在计算过程中,这些未匹配的左括号实际上限制了有效括号子串的起始位置。任何有效子串都不能包括这些未匹配的左括号,只能从它们之后的位置开始。因此,在计算有效括号长度时,这些左括号的位置会作为一个新的起点来计算长度,这可能导致有效括号子串的长度减少。
🦆
在计算最长有效括号子串长度时,为什么使用`i - top`而不是其他计算方式?
使用`i - top`计算方式是因为,当栈中的顶部元素(即最近一个匹配的左括号的索引)被弹出后,新的栈顶元素(如果存在)就表示当前考虑的右括号之前的最近一个未匹配的左括号的位置。因此,当前有效的括号子串是从栈顶元素的下一个位置开始,直到当前右括号的位置。这使得`i - top`成为计算当前有效子串长度的正确方法。如果栈为空,则使用j作为起始位置,因为这表示之前所有的括号都已匹配完毕,新的子串开始于最后一个未匹配右括号之后。
🦆
代码中的`top`变量在栈为空后是如何处理的,为何可以直接使用j作为新的起点?
在代码中,当栈为空且遇到一个有效的右括号时,`top`变量需要指向一个合适的起点,以便计算有效括号子串的长度。在这种情况下,使用变量j作为新的起点,因为j已经被更新为最后一个无效的右括号的索引。因此,任何新的有效子串都应该从j的下一个位置开始计算。这样,`top`变在栈为空时使用j作为新的起点,确保了有效子串的长度能够正确计算,避免了包含之前无效的右括号在内的计算错误。

相关问题

有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

 

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

示例 3:

输入:s = "(]"
输出:false

 

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成