32. 最长有效括号

文章介绍了一种使用动态规划解决寻找给定字符串中最长有效括号子串长度的方法。通过遍历字符串,根据遇到的左括号和右括号更新状态转移矩阵dp,以找到最长有效括号子串。关键在于状态转移方程dp[i]=dp[i-1]+2+((pre-1)>0?dp[pre-1]:0),其中pre表示与当前右括号匹配的左括号位置。
摘要由CSDN通过智能技术生成

32. 最长有效括号

难度困难2251

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

示例 1:

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

示例 2:

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

示例 3:

输入:s = ""
输出:0

提示:

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

动态规划

dp定义 : 以s[i]为结尾的字符串,往左最远能推多远 使得是最长的有效括号 该位置的最长有效括号长度就是dp[i]

注意只要是 子串,子序列-->最长.....定义dp数组的定义一般都是以xxx为结尾向左能推多远,并且动态规划的特点要借助前面的答案能推出当前位置的答案,进而从前往后推,推到最后,最终就是答案了....

我们来分析一下题意 :

首先遍历字符串从前往后推导,要么遇到的是左括号,要么遇到的是右括号

  • 如果遇到的是左括号,无论怎么往前推都找不到匹配的,左括号无法匹配
  • 如果遇到的是右括号,那就要往左推导了
    • 首先我们要找到与当前右括号匹配的左括号的位置
  • 当我们找到了与与当前右括号匹配的左括号的位置,答案就是 dp[i-1] + 2,难道这就是答案么 ?

 综上 最长有效括号长度状态转移方程为 :  dp[i] = dp[i-1] + 2 + ((pre-1)>=0 ? dp[pre-1] :0);

dp[i-1] + 2 是指当前右括号找到前面匹配的左括号所以是s[i-1]匹配的有效长度再加上2就是当前最长有效括号长度

dp[pre-1] : 前面可能还有合法的括号,我们也要把它加上 --> dp[pre-1]-->前提是pre合法

class Solution {
    public int longestValidParentheses(String s) {
        if(s==null || s.length() <2) {
            return 0;
        }
        int n = s.length();
        //dp : 以s[i]为结尾的字符串,往左最远能推多远使得是最长的有效括号
        int[] dp = new int[n];
        int res = 0;
        int pre = 0;//记录与当前右括号匹配的左括号的位置
        for(int i =1;i<n;++i) {
            //如果当前是左括号则,往左不可能找到匹配的dp[i]= 0;
            if(s.charAt(i) == ')') {
                //如果当前是右括号
                // (  (  (  )  )  )
                // 0  1  2  3  4  5
                // 0  0  0  2  4  5 - dp[i-1](4) - 1 = 0
                pre = i - dp[i-1] -1;//记录与当前右括号匹配的左括号的位置
                // 不能匹配 : pre<0
                // (  (  )  )  )
                // 0  1  2  3  4 
                // 0  0  2  4  4 - dp[i-1](4) - 1 = -1-->当前括号是单独的右括号
                //不能匹配 : pre是右括号的
                // )  (  )  ) 
                // 0  1  2  3
                // 0  0  2  3 - dp[i-1](2) - 1 = 0 --->但s[pre]是右括号与当前右括号不匹配
                if(pre >=0 && s.charAt(pre) == '(') {
                    //与当前右括号匹配的位置必须合法,并且该位置是与右括号匹配的左括号
                    // (  )  (  (  (  )  )  )
                    // 0  1  2  3  4  5  6  7
                    // 0  2  0  0  0  2  4  7 - dp[i-1](4) - 1 = 2(与当前右括号匹配的位置并且合法并且匹配)
                    // 因为此时当前 (  (  (  )  )  ) 前面可能还有合法的括号,我们也要把它加上 --> dp[pre-1]-->前提是pre合法
                    //dp[i-1] + 2 是指当前右括号找到前面匹配的左括号所以是s[i-1]匹配的有效长度再加上2就是当前最长有效括号长度
                    //dp[pre-1] : 前面可能还有合法的括号,我们也要把它加上 --> dp[pre-1]-->前提是pre合法
                    dp[i] = dp[i-1] + 2 + ((pre-1)>=0 ? dp[pre-1] :0);
                }
            }
            res = Math.max(dp[i],res);
        }
        return res;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值