
动态规划代码1:
- dp[i] 表示以下标 i 字符结尾的最长有效括号
- 如果 s[i] 是 '(' 结尾则对应的dp一定是 0 ,这种情况不考虑
- 当 s[i] == ')' , 则需要判断 s[i-1] 是什么,如果是 '(' ,则状态转移
dp[i] = dp[i-2] + 2
- 如果 s[i-1] 是 ')' 且
s[i - dp[i-1]-1] == '(' , 也就是去除前面已成型的括号,那么状态转移 dp[i] = dp[i-1] + dp[i-dp[i-1]-2] + 2
- 当然在状态转移的时候,要保证下标合法
- ans则维护dp中的最大值
func longestValidParentheses(s string) int {
ans := 0
n := len(s)
if n < 2 {
return 0
}
dp := make([]int, n)
if s[:2] == "()" {
dp[1] = 2
ans = 2
}
for i := 2; i < n; i++ {
if s[i] == ')' {
if s[i-1] == '(' {
dp[i] = dp[i-2] + 2
}else if i - dp[i-1] -1 >= 0 && s[i - dp[i-1]-1] == '(' {
if i - dp[i-1] - 2 >= 0 {
dp[i] = dp[i-1] + dp[i-dp[i-1]-2] + 2
}else {
dp[i] = dp[i-1] + 2
}
}
ans = max(ans, dp[i])
}
}
return ans
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
栈代码2:
- stk数组模拟栈,保存 '(' 的下标,其中栈底保存多余的右括号的位置,初始为-1
- 遍历,碰到 ')' 则弹出栈顶元素,如果栈为空,则将下标压入栈,意味着栈从这里重置,因为遇到了多余的右括号,
- 如果栈不为空则维护ans的最大值
func longestValidParentheses(s string) int {
ans := 0
stk := []int{-1}
for i, v := range s {
if v == '(' {
stk = append(stk, i)
}else {
stk = stk[:len(stk)-1]
if len(stk) == 0 {
stk = append(stk, i)
}else {
ans = max(ans, i - stk[len(stk)-1])
}
}
}
return ans
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
代码3:
- a , b 用来记录左右括号的数量,当数量相等的时候维护一次最大值
- 当左括号数量小于右括号数量则置0,原因其实与前两个方法一致,因为不论后面再出现什么符号,它都无效
- 但这种方法有一种情况无法记录,那就是左括号的数量一直大于右括号的数量
- 所以为了考虑这种情况,我们可以将s字符串从左往右倒着来一遍1,2,3的步骤
func longestValidParentheses(s string) int {
ans := 0
a, b := 0, 0
for _,v := range s {
if v == '(' {
a++
}else {
b++
}
if a == b{
ans = max(ans, a * 2)
}else if a < b {
a, b = 0, 0
}
}
a, b = 0, 0
for i := len(s)-1; i >= 0; i-- {
if s[i] == ')' {
b++
}else {
a++
}
if b == a {
ans = max(ans, b * 2)
}else if a > b {
a, b = 0, 0
}
}
return ans
}
func max(a, b int) int {
if a > b {
return a
}
return b
}