32 最长有效括号-求长度

题目

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

示例

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

解析

看到这道题的时候是在动态规划的部分,但实际上对于括号的的这种题,更容易想到的是栈,那么先说一下栈的做法:

具体做法是我们始终保持栈底元素为当前已经遍历过的元素中「最后一个没有被匹配的右括号的下标」,这样的做法主要是考虑了边界条件的处理,栈里其他元素维护左括号的下标:

  • 对于遇到的每个 ‘(’ ,我们将它的下标放入栈中
  • 对于遇到的每个 ‘)’ ,我们先弹出栈顶元素表示匹配了当前右括号:
    • 如果栈为空,说明当前的右括号为没有被匹配的右括号,我们将其下标放入栈中来更新我们之前提到的「最后一个没有被匹配的右括号的下标」
    • 如果栈不为空,当前右括号的下标减去栈顶元素即为「以该右括号为结尾的最长有效括号的长度」
      我们从前往后遍历字符串并更新答案即可。

需要注意的是,如果一开始栈为空,第一个字符为左括号的时候我们会将其放入栈中,这样就不满足提及的「最后一个没有被匹配的右括号的下标」,为了保持统一,我们在一开始的时候往栈中放入一个值为 −1 的元素。

func longestValidParentheses(s string) int {
	maxAns := 0
	stack := []int{}
	stack = append(stack, -1)
	for i := 0; i < len(s); i++ {
		if s[i] == '(' {
			stack = append(stack, i) // 下标入栈
		} else {
			stack = stack[:len(stack)-1] // 注意,右括号的时候已经先匹配左括号弹出了,下面的所有逻辑就是在弹出的基础上
			if len(stack) == 0 {
				stack = append(stack, i)
			} else {
				maxAns = max(maxAns, i-stack[len(stack)-1]) // 当前遍历到的右括号的下标 - 栈的最后一个元素(栈顶元素)
			}
		}
	}
	return maxAns
}

至于动态规划的方式,属实是看得比较困惑,直接把答案放这了:

func longestValidParentheses(s string) int {
	n := len(s)
	maxAns := 0
	dp := make([]int, len(s)) // dp[i]表示下标为i结尾的字符串最长有效括号长度
	for i := 1; i < n; i++ {
		if s[i] == ')' { // 左括号不用处理,相当于直接dp[i] = 0了
			if s[i-1] == '(' {
				if i > 2 {
					dp[i] = dp[i-2] + 2
				} else {
					dp[i] = 2
				}
			} else if i-dp[i-1] > 0 && s[i-dp[i-1]-1] == '(' {
				if i-dp[i-1] >= 2 {
					dp[i] = dp[i-1] + dp[i-dp[i-1]-2] + 2
				} else {
					dp[i] = dp[i-1] + 2
				}
			}
			maxAns = max(maxAns, dp[i])
		}
	}
	return maxAns
}

两篇看的似懂非懂的题解:
https://leetcode.cn/problems/longest-valid-parentheses/solutions/206995/dong-tai-gui-hua-si-lu-xiang-jie-c-by-zhanganan042/?envType=study-plan-v2&envId=top-100-liked
https://leetcode.cn/problems/longest-valid-parentheses/solutions/314683/zui-chang-you-xiao-gua-hao-by-leetcode-solution/?envType=study-plan-v2&envId=top-100-liked

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值