longest valid parentheness 最长有效括号问题

https://leetcode.com/problems/longest-valid-parentheses/

题目要求:

        输入一个字符串s,里面在只包含两种字符 '('和 ')',例如s=“(()))(()”

        找到最长的一个子串,且其包含的括号成对合法出现,例如s中的第2到3个字符子串“()”,但它不是最长的,最长的是第1到4个字符子串“(())”。

解题思路:

        动态规划+字符串操作

       动态规划的关键是为s建立一张表,用来记录遍历过的字符相对应的重要信息。表的含义有多种,因此选择何种含义是最为关键。好的含义往往事半功倍。以本题为例,一开始的思路是确定使用动态规划方法,但dp是个大概念,具体到每个题目就必须有详细的分析。首先,想到是定义两个表maxlen和pos,然后从左往右遍历s,其中maxlen[i]和pos[i]分别表示从第0到i个字符子串内的最大括号对的长度和位置,但具体分析下去发现情况十分复杂,分支太多。

       因此,参考网上的其他高手的想法。重新定义一个maxlen,maxlen[i]表示包含s[i]且向左延伸的最长合法括号对的长度。这里补充一句,如果第一次定义的表不好用,那么在钻研一段时间后,应该考虑重新定义,正所谓条条大路通罗马哈。问题的关键来了,如果使用和给这张表赋值,分以下这几种情况:

1. s[i]=='('

    很明显,没有以'('结尾的合法括号对,所以maxlen[i]=0;

2. s[i]==')'

     如果能够找到一个与')'(s[i])配对的‘(’,且左右括号内的字符串是合法的,s[i]肯定是不等于0的(具体值请见下文),否则置为0。

     与s[i]=')'配对的'('出现的位置有三种可能,a.不存在,b.s[i-1], c.s[i-1]往左的位置,即小于i-1

a。s[i]=0

b。maxlen[i]=2+maxlen[i-2];(前提:i-2的位置存在),这个很好理解,符合maxlen[i]的含义

c。如果b不成立,说明s[i-1]=')',那么此时与s[i]配对的‘(’肯定是在s[i-1]的“左边”。

      这个“左边”可以分为:在s[i-1]对应于的最长括号对内,即s[ i-maxlen[i-1], i-1 ];不在s[ i-maxlen[i-1], i-1 ]内。

      如果在,显然不合理。原因如下:

      如果与s[i]配对的‘(’在s[ i-maxlen[i-1], i-1 ]中,那么本来与‘(’配对的')'便会不合法。

      因此,应该不在s[ i-maxlen[i-1], i-1 ]内,即从s[i-1-maxlen[i-1]]开始向左一次判断是否等于'('。

      如果s[i-1-maxlen[i-1]]==‘(’,那么s[i]=2+maxlen[i-1]+maxlen[i-2-maxlen[i-1]](前提:i-2-maxlen[i-1]位置存在),否则说明s[i-1-maxlen[i-1]]==‘)’。根据前面的叙述,应该继续递归查找s[i-1-maxlen[i-1]]往左的内容。但是,仔细观察便会发现递归的结果依然是判断s[i-1-maxlen[i-1]],然而s[i-1-maxlen[i-1]]已经等于‘)’,说明不存在与s[i]配对的‘(’,即情况a,那么s[i]=0。

代码如下:

class Solution {
public:
    int longestValidParentheses(string s) {
        if(s.size()<=1) return 0;
        
        int res(0);
        vector<int> maxlen(s.size(), 0);
        for(int i=1; i<s.size(); i++){
            if(s[i]==')'){
                if(s[i-1]=='('){
                    maxlen[i]= 2+( i-2>=0 ? maxlen[i-2] :0 );
                }
                else if(i-1-maxlen[i-1]>=0 && s[i-1-maxlen[i-1]]=='('){
                    maxlen[i]=2+maxlen[i-1]+( i-2-maxlen[i-1]>=0 ? maxlen[i-2-maxlen[i-1]] : 0 );
                }
            }
            res=max(res, maxlen[i]);
        }
        
        return res;
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值