leetCode32: 最长有效括号

自我总结使用 

作者:LeetCode-Solution

链接:https://leetcode.cn/problems/longest-valid-parentheses/solution/zui-chang-you-xiao-gua-hao-by-leetcode-solution/

来源:力扣(LeetCode)

//方法1 动态规划
func longestValidParentheses(s string) int {
    //动态规划公式:dp[i] = 2 + dp[i-1] + dp[i-dp[i-1]-2]
    var max int
    length := len(s)
    if length < 2 {
        return 0
    }
    dp := make([]int, length)
    //这里i从1开始是因为go切片index从0开始
    for i := 1; i < length; i ++ {
        //判断最长子串dp结尾是不是右括号
        if string(s[i]) == ")" {
            //判断前一个是不是左括号
            if string(s[i-1]) == "(" {
                //当前括号的数量是不是大于4个 才能涉及到状态转换方程公式
                if i - 1 >= 2 {
                    //这里我理解是连续的括号 2是本身()长度为2 
                    //再加上当前索引向前推2个就是前一个括号的索引位置子串最大长度
                    dp[i] = 2 + dp[i-2]
                }else{
                    //只有一对括号的时候长度就是2
                    dp[i] = 2
                }
            }else{
                //这里如果有连续的右括号说明可能有连续的左括号 那么需要找到满足成对数量的最左侧的左括号(索引是:i-dp[i-1]-1)
                //因为这个左括号索引不能为负数 索引判断大于等于0 满足大于等于0之后就去找这个位置是不是左括号
                if i - dp[i-1] >= 1 && string(s[i-dp[i-1]-1]) == "(" {
                    //这里为了满足go 切片索引从0开始 所以对dp[i-dp[i-1]-2]中索引判断大于等于0 简化就是下面写法
                    if i - dp[i-1] >= 2 {
                        //满足公式说明左侧有最长子串长度的dp数值 但是整个数值不一定就是大于0的 个人理解
                        dp[i] = 2 + dp[i-1] + dp[i-dp[i-1]-2]
                    }else{
                        //不满足说明左侧只有最左侧的当前这个左括号了也就不需要考虑dp[i-dp[i-1]-2]这部分了
                        dp[i] = 2 + dp[i-1]
                    }
                }
            }
        }
        //综上所述 取最大长度即可
        if max < dp[i] {
            max = dp[i]
        }
    }
    return max
}

//方法2 栈
func longestValidParentheses(s string) int {
    var max, maxLength int
    length := len(s)
    var stack []int
    //使用-1来先入栈 作为后续计算最大长度使用
    stack = append(stack, -1)
    for i:=0; i<length; i++ {
        if string(s[i]) == "(" {
            //左括号入栈
            stack = append(stack, i)
        }else{
            if len(stack) == 0 {
                stack = append(stack, i)
                max = 0
            }else{
                if stack[len(stack)-1] == -1 {
                    stack = []int{}
                    stack = append(stack, i)
                }else{
                    if string(s[stack[len(stack)-1]]) == "(" {
                        stack = stack[:len(stack)-1]
                        //这里max计算是 用当前的索引将或者连续左括号弹出取下一个索引相差就是max
                        max = (i - stack[len(stack)-1])
                    }else{
                        stack = append(stack, i)
                    }
                }
            }
        }
        if maxLength < max {
            maxLength = max
        }
    }
    return maxLength
}

//方法三 正向逆向结合法
func longestValidParentheses(s string) int { 
    if len(s) < 2 {
        return 0
    }
    leftNum, rightNum, maxLength := 0,0,0
    //每次遍历比较左右括号数量
    //正向比较右括号大于左括号数量 左右括号计数清0
    //逆向与之相反
    for i := 0; i < len(s); i++ {
        if string(s[i]) == "(" {
            leftNum++
        }else{
            rightNum++
        }
        if rightNum == leftNum {
            if maxLength < leftNum {
                maxLength = leftNum
            }
        }
        if rightNum > leftNum {
            leftNum = 0
            rightNum = 0
        }
    }
    leftNum1, rightNum1, maxLength1 := 0,0,0
    for i:= len(s)-1; i >= 0; i-- {
        if string(s[i]) == ")" {
            rightNum1++
        }else{
            leftNum1++
        }
        if leftNum1 == rightNum1 {
            if maxLength1 < leftNum1 {
                maxLength1 = leftNum1
            }
        }
        if leftNum1 > rightNum1 {
            leftNum1=0
            rightNum1=0
        }
    }
    if maxLength > maxLength1 {
        return maxLength*2
    }else{
        return maxLength1*2
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值