LeetCode 32. 最长有效括号【c++/java详细题解】

1、题目

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

示例 1:

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

示例 2:

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

示例 3:

输入:s = ""
输出:0

提示:

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

2、思路

(栈) O ( n ) O(n) O(n)

我们可以发现一个规律,每一段合法括号序列它在字符串s中出现的位置一定是连续且不相交的,如下图所示:

因此我们能想到的最直接的做法是找到每个可能的子串后判断它是否为合法括号序列,但这样的时间复杂度会达到 O ( n 3 ) O(n^3) O(n3)

有没有一种更高效的做法?

我们知道栈在处理括号匹配有着天然的优势,于是考虑用栈去判断序列的合法性。遍历整个字符串s,把所有的合法括号序列按照右括号来分类,对于每一个右括号,都去求一下以这个右括号为右端点的最长的合法括号序列的左端点在什么位置。我们把每个右括号都枚举一遍之后,再取一个max,就是整个的最大长度。

具体过程如下:

  • 1、用栈维护当前待匹配的左括号的位置,同时用 start 记录一个新的可能合法的子串的起始位置,初始设为0

  • 2、如果s[i] =='(',那么把i进栈。

  • 3、如果s[i] == ')',那么弹出栈顶元素 (代表栈顶的左括号匹配到了右括号),出栈后:

    • 如果栈为空,说明以当前右括号为右端点的合法括号序列的左端点为start,则更新答案 i - start + 1

    • 如果栈不为空,说明以当前右括号为右端点的合法括号序列的左端点为栈顶元素的下一个元素,则更新答案i - st.top()

  • 4、遇到右括号)且当前栈为空,则当前的 start开始的子串不再可能为合法子串了,下一个合法子串的起始位置是 i + 1,更新 start = i + 1

  • 5、最后返回答案即可。

实现细节: 栈保存的是下标。

时间复杂度分析: 每个位置遍历一次,最多进栈一次,故时间复杂度为 O ( n ) O(n) O(n)

3、c++代码

class Solution {
public:
    int longestValidParentheses(string s) {
        stack<int> st;
        int ans = 0;
        for (int i = 0,start = 0; i < s.size(); i++) 
        {
            if (s[i] == '(') st.push(i);    //左括号入栈            
            else 
            {
                if (!st.empty()) 
                {
                    st.pop();	//匹配成功
                    if (st.empty()) ans = max(ans, i - start + 1);
                    else  ans = max(ans, i - st.top()); //i - st.top() + 1 - 1
                }
                else  start = i + 1;  //更新起点                      
            }
        }
        return ans;
    }
};

4、java代码

class Solution {
    public int longestValidParentheses(String s) {
        Stack<Integer> st = new Stack<Integer>();
        int ans = 0;
        for(int i = 0 ,start = 0;i < s.length();i ++)
        {
            if( s.charAt(i) == '(') st.add(i);
            else
            {
                if(!st.isEmpty()) 
                {
                    st.pop();
                    if(st.isEmpty()) ans = Math.max(ans,i - start + 1);
                    else ans = Math.max(ans,i - st.peek());
                }
                else start = i + 1;
            }
        }
        return ans;
    }
}

原题链接: 32. 最长有效括号

在这里插入图片描述

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

林小鹿@

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值