leetcode 32. 最长有效括号 hard

leetcode 32. 最长有效括号  hard          

题目描述:

给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。

示例 1:

输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
示例 2:

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

解题思路:

方法一: nb解法 

一个括号序列有两个很重要的性质: 

  1. 不管我们怎么找有效的子串,一个特定的左括号跟它匹配的右括号总是不变的。比如()()(())) 不管怎么找,标红的两个括号总是匹配在一起的。 并且(很重要) 在总的序列一个没法找到匹配的左括号or右括号,你在任何子串中也无法找到一个跟他匹配的右括号or左括号,比如上面例子的最后一个右括号
  2. 括号序列合法 等价于 所有前缀和>=0,且总和等于0(把左括号看出1,右括号看成-1)(重要)

所以我们

简单的说就是这一部分如果出现问题了,那肯定最后一位是右括号,并且是因为这个右括号没人匹配导致的,那么这一部分就可以直接放弃了,因为不会被匹配的右括号永远不会被匹配。

不过从左到右遍历 只能统计总的右括号数目大于等于左括号的情况,但是对于(((()) 这种却无能为力,所以我们需要从右边到左边再来一次(注意, 反着做把右括号看成1,左括号看成-1)

方法二:dp

这道题最重要的就是教会我,不管乱七八糟的,一定要记住数组别越界(还有假如求什么最长的,先想dp)

方法三:

用栈来做, 其实更推荐用这个方法。

代码:

//nb解法
class Solution {
public:
    int longestValidParentheses(string s) {
        
        int start=0;
        int cnt=0; // 前缀和
        int res=0;
        // 正着做 
        for(int i=0;i<s.size();++i){
            if(s[i]=='(') cnt++;
            else{
                cnt--;
                if(cnt<0){ start=i+1;cnt=0;} 
                else if(cnt==0) res=max(res,i-start+1); 
            }
        }
        
        // 反着做
        int end=s.size()-1;
        cnt=0;
        for(int i=end;i>=0;--i){
            if(s[i]==')') cnt++;   // 反着做把右括号看成1,左括号看成-1
            else{
                cnt--;
                if(cnt<0) {end=i-1;cnt=0;}
                else if(cnt==0) res=max(res,end-i+1);
            }
        }
        
        return res;
        
        
        
    }
};


//dp
class Solution {
public:
    int longestValidParentheses(string s) {
        
        vector<int> dp(s.size(),0);
        
        int maxlen=0;
        // 以每个位置为尾的最长有效括号的长度
        for(int i=1;i<s.size();++i){
            if(s[i]==')' && s[i-1]=='(')
                dp[i]= (i>=2?dp[i-2]:0)+2;
            else if(s[i]==')' && s[i-1]==')'){
                // 别管乱七八糟的 别越界就行
                if(i-1-dp[i-1]>=0 && s[i-1-dp[i-1]]=='(')
                    dp[i]=dp[i-1] + 2+ (i-2-dp[i-1]>=0?dp[i-2-dp[i-1]]:0);  // 别忘了加上 最后一个表达式
            }
            
            maxlen=max(maxlen,dp[i]);
        }
        
        return maxlen;
        
    }
};

栈作法:

class Solution {
public:
    int longestValidParentheses(string s) {

        stack<int> stk;
        int start = 0;
        int ret = 0;
        for (int i = 0; i < s.size(); i++){
            if (s[i] == '('){
                stk.push(i);
            } else if (stk.empty()) {
                start = i+1;
            } else {
                stk.pop();
                int one = stk.empty()? i-start+1: i-stk.top();
                ret = max(ret, one);
            }
        }
        
        return ret;

    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值