LeetCoder_____ 最长有效括号(32)

本文探讨了两种解决最长有效括号问题的算法思路。思路A利用栈和数组记录括号匹配过程,通过统计连续非零值求得最长有效括号长度。思路B则采用区间扩展方法,从左至右寻找并扩展有效括号区间,实现高效求解。

1. 思路A

一般来说括号这种匹配的一般都是用栈来验证,但是这里如何统计最长有效的括号呢?
下面给出一种方法:

准备栈A和数组B,逐个读入字符串字符c,如果栈顶元素和当前字符c不可以匹配’(’ 和 ‘)’;那么就将当前字符压入栈,并且在数组B中追加一个0;如果可以匹配,那么就将栈顶元素弹出,并且将栈顶对应压入B数组的0改为2。最后统计B数组中连续不为0的数的和即可。

拿"(())(()"举例子:

  1. 当前字符为 ( ,栈无元素,不能匹配;栈压入(,数组压入0
    A : (
    B : 0
  2. 当前字符为 ( ,栈顶为 (,不能匹配;栈压入(,数组压入0
    A : ((
    B : 0 0
  3. 当前字符为 ) ,栈顶为 (,可以匹配;栈弹出(,数组对应0改为2
    A : (
    B : 0 2
  4. 当前字符为 ) ,栈顶为 (,可以匹配;栈弹出(,数组对应0改为2
    A :
    B : 2 2
  5. 当前字符为 ( ,栈无元素,不能匹配;栈压入(,数组压入0
    A : (
    B : 2 2 0
  6. 当前字符为 ( ,栈顶为 (,不能匹配;栈压入(,数组压入0
    A : ((
    B : 2 2 0 0
  7. 当前字符为 ) ,栈顶为 (,可以匹配;栈弹出(,数组对应0改为2
    A : (
    B : 2 2 0 2

最后观察,B数组最大连续不为0的和为4,表示最长有效括号为4。




2. 代码A

class Solution {
public:
    int longestValidParentheses(string s) {
        stack<int> zero;
        vector<int> data;
        int ret = 0, num = 0;;
        for(int i = 0; i < s.length(); ++i)
        {
            if(zero.empty() || !(s[i] == ')' && data[zero.top()] == -1))
            {
                zero.push(data.size());
                data.push_back(s[i] == '(' ? -1 : -2);
                
            }
            else
            {
                data[zero.top()] = 2;
                zero.pop();
            }
        }
        for(int i = 0; i < data.size(); ++i)
        {
            num = data[i] < 0 ? 0 : num + data[i];
            ret = max(num, ret);
        }
        return ret;
    }
};




3. 思路B

因为以前做括号这类题目基本都是用区间dp或者栈,所以先入为主的只想到了方法A,不过在和朋友聊这个题的时候,朋友提供了另一个思路。

1.从左往右找第一个完整括号(),然后向两边扩展直到不能形成更大的有效括号然后记住这个区间[l,r]。
2.然后从区间r右边继续找完整括号(),重复前面1的操作,只不过需要注意,当左边可以跟之前任何一个区间[l,r]的相连接时,就可以连接之前的区间,形成更长的有效括号。

还是拿个字符串举例子"(())(()())"

  1. 第一个找到的完整括号是[1,2],然后此时向两边扩展到[0,3]。记录一下。
  2. 从3开始继续找完整括号[5,6],然后扩展到[5,8],继续[4,9],此时已经不能扩展了,但是我们发现[4,9]和前面的[0,3]可以连起来,所以形成了更大的[0,9]。然后也没法继续拓展了,再记录一下。

最后将所有记录过的区间,求长度最长的区间即可。




4. 代码B

class Solution {
public:
    int longestValidParentheses(string s) {
        stack<int> prel;
        stack<int> prer;
        int l = 0, r = 0, ret = 0, length = s.length();
        while(true)
        {
            if(r + 1 > length) break;

            if(s[r] =='(' && s[r+1] == ')')
            {
                
                l = r; r = r + 1;
                while(true)
                {
                    if(!prer.empty() && prer.top() == l - 1){
                        l = prel.top(); prel.pop(); prer.pop();
                    }
                    else if(l-2 >= 0 && s[l-2] == '(' && s[l-1] == ')') l -= 2;
                    else if(r+2 < length && s[r+1] == '(' && s[r+2] == ')') r += 2;
                    else if(l-1 >= 0 && r+1 < length && s[l-1] == '(' && s[r+1] == ')') l --, r ++;
                    else break;
                }
                
                ret = max(ret, r - l + 1);
                prel.push(l);prer.push(r);
            }
            r ++;
        }
        return ret;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值