Skip to content

Files

0032.Longest Valid Parentheses

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Dec 10, 2023
Dec 10, 2023
Jun 18, 2023
Jun 18, 2023
Nov 10, 2023
Jun 18, 2023
Jun 18, 2023
Jun 18, 2023
Dec 9, 2023
Apr 11, 2023

English Version

题目描述

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

 

示例 1:

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

示例 2:

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

示例 3:

输入:s = ""
输出:0

 

提示:

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

解法

方法一:动态规划

我们定义 f [ i ] 表示以 s [ i 1 ] 结尾的最长有效括号的长度,那么答案就是 max i = 1 n f [ i ]

  • 如果 s [ i 1 ] 是左括号,那么以 s [ i 1 ] 结尾的最长有效括号的长度一定为 0 ,因此 f [ i ] = 0
  • 如果 s [ i 1 ] 是右括号,有以下两种情况:
    • 如果 s [ i 2 ] 是左括号,那么以 s [ i 1 ] 结尾的最长有效括号的长度为 f [ i 2 ] + 2
    • 如果 s [ i 2 ] 是右括号,那么以 s [ i 1 ] 结尾的最长有效括号的长度为 f [ i 1 ] + 2 ,但是还需要考虑 s [ i f [ i 1 ] 2 ] 是否是左括号,如果是左括号,那么以 s [ i 1 ] 结尾的最长有效括号的长度为 f [ i 1 ] + 2 + f [ i f [ i 1 ] 2 ]

因此,我们可以得到状态转移方程:

{ f [ i ] = 0 , if  s [ i 1 ] = ( , f [ i ] = f [ i 2 ] + 2 , if  s [ i 1 ] = )  and  s [ i 2 ] = ( , f [ i ] = f [ i 1 ] + 2 + f [ i f [ i 1 ] 2 ] , if  s [ i 1 ] = )  and  s [ i 2 ] = )  and  s [ i f [ i 1 ] 2 ] = ( ,

最后返回 max i = 1 n f [ i ] 即可。

时间复杂度 O ( n ) ,空间复杂度 O ( n ) 。其中 n 为字符串的长度。

方法二:使用栈

  • 使用栈来存储左括号的索引,栈底元素初始化为 -1,用于辅助计算有效括号的长度。
  • 遍历字符串,对于每个字符:
    • 如果是左括号,将当前位置压入栈。
    • 如果是右括号,弹出栈顶元素表示匹配了一个左括号。
      • 如果栈为空,说明当前右括号无法匹配,将当前位置压入栈作为新的起点。
      • 如果栈不为空,计算当前有效括号子串的长度,更新最大长度。
  • 最终返回最大长度。

总结:这个算法的关键在于维护一个线,栈内存放的是左括号的索引,通过弹出和压入的操作来更新有效括号子串的长度。

时间复杂度 O ( n ) ,空间复杂度 O ( n ) 。其中 n 为字符串的长度。

Python3

class Solution:
    def longestValidParentheses(self, s: str) -> int:
        n = len(s)
        f = [0] * (n + 1)
        for i, c in enumerate(s, 1):
            if c == ")":
                if i > 1 and s[i - 2] == "(":
                    f[i] = f[i - 2] + 2
                else:
                    j = i - f[i - 1] - 1
                    if j and s[j - 1] == "(":
                        f[i] = f[i - 1] + 2 + f[j - 1]
        return max(f)
class Solution:
    def longestValidParentheses(self, s: str) -> int:
        stack = [-1]
        ans = 0
        for i in range(len(s)):
            if s[i] == '(':
                stack.append(i)
            else:
                stack.pop()
                if not stack:
                    stack.append(i)
                else:
                    ans = max(ans, i - stack[-1])
        return ans

Java

class Solution {
    public int longestValidParentheses(String s) {
        int n = s.length();
        int[] f = new int[n + 1];
        int ans = 0;
        for (int i = 2; i <= n; ++i) {
            if (s.charAt(i - 1) == ')') {
                if (s.charAt(i - 2) == '(') {
                    f[i] = f[i - 2] + 2;
                } else {
                    int j = i - f[i - 1] - 1;
                    if (j > 0 && s.charAt(j - 1) == '(') {
                        f[i] = f[i - 1] + 2 + f[j - 1];
                    }
                }
                ans = Math.max(ans, f[i]);
            }
        }
        return ans;
    }
}

C++

class Solution {
public:
    int longestValidParentheses(string s) {
        int n = s.size();
        int f[n + 1];
        memset(f, 0, sizeof(f));
        for (int i = 2; i <= n; ++i) {
            if (s[i - 1] == ')') {
                if (s[i - 2] == '(') {
                    f[i] = f[i - 2] + 2;
                } else {
                    int j = i - f[i - 1] - 1;
                    if (j && s[j - 1] == '(') {
                        f[i] = f[i - 1] + 2 + f[j - 1];
                    }
                }
            }
        }
        return *max_element(f, f + n + 1);
    }
};

Go

func longestValidParentheses(s string) int {
	n := len(s)
	f := make([]int, n+1)
	for i := 2; i <= n; i++ {
		if s[i-1] == ')' {
			if s[i-2] == '(' {
				f[i] = f[i-2] + 2
			} else if j := i - f[i-1] - 1; j > 0 && s[j-1] == '(' {
				f[i] = f[i-1] + 2 + f[j-1]
			}
		}
	}
	return slices.Max(f)
}
func longestValidParentheses(s string) int {
	ans := 0
	stack := []int{-1}
	for i, v := range s {
		if v == '(' {
			stack = append(stack, i)
		} else {
			stack = stack[:len(stack)-1]
			if len(stack) == 0 {
				stack = append(stack, i)
			} else {
				if ans < i-stack[len(stack)-1] {
					ans = i - stack[len(stack)-1]
				}
			}
		}
	}
	return ans
}

C#

public class Solution {
    public int LongestValidParentheses(string s) {
        int n = s.Length;
        int[] f = new int[n + 1];
        int ans = 0;
        for (int i = 2; i <= n; ++i) {
            if (s[i - 1] == ')') {
                if (s[i - 2] == '(') {
                    f[i] = f[i - 2] + 2;
                } else {
                    int j = i - f[i - 1] - 1;
                    if (j > 0 && s[j - 1] == '(') {
                        f[i] = f[i - 1] + 2 + f[j - 1];
                    }
                }
                ans = Math.Max(ans, f[i]);
            }
        }
        return ans;
    }
}

TypeScript

function longestValidParentheses(s: string): number {
    const n = s.length;
    const f: number[] = new Array(n + 1).fill(0);
    for (let i = 2; i <= n; ++i) {
        if (s[i - 1] === ')') {
            if (s[i - 2] === '(') {
                f[i] = f[i - 2] + 2;
            } else {
                const j = i - f[i - 1] - 1;
                if (j && s[j - 1] === '(') {
                    f[i] = f[i - 1] + 2 + f[j - 1];
                }
            }
        }
    }
    return Math.max(...f);
}
function longestValidParentheses(s: string): number {
    let max_length: number = 0;
    const stack: number[] = [-1];
    for (let i = 0; i < s.length; i++) {
        if (s.charAt(i) == '(') {
            stack.push(i);
        } else {
            stack.pop();

            if (stack.length === 0) {
                stack.push(i);
            } else {
                max_length = Math.max(max_length, i - stack[stack.length - 1]);
            }
        }
    }

    return max_length;
}

JavaScript

/**
 * @param {string} s
 * @return {number}
 */
var longestValidParentheses = function (s) {
    const n = s.length;
    const f = new Array(n + 1).fill(0);
    for (let i = 2; i <= n; ++i) {
        if (s[i - 1] === ')') {
            if (s[i - 2] === '(') {
                f[i] = f[i - 2] + 2;
            } else {
                const j = i - f[i - 1] - 1;
                if (j && s[j - 1] === '(') {
                    f[i] = f[i - 1] + 2 + f[j - 1];
                }
            }
        }
    }
    return Math.max(...f);
};
/**
 * @param {string} s
 * @return {number}
 */
var longestValidParentheses = function (s) {
    let ans = 0;
    const stack = [-1];
    for (i = 0; i < s.length; i++) {
        if (s.charAt(i) === '(') {
            stack.push(i);
        } else {
            stack.pop();
            if (stack.length === 0) {
                stack.push(i);
            } else {
                ans = Math.max(ans, i - stack[stack.length - 1]);
            }
        }
    }
    return ans;
};

Rust

impl Solution {
    pub fn longest_valid_parentheses(s: String) -> i32 {
        let mut ans = 0;
        let mut f = vec![0; s.len() + 1];
        for i in 2..=s.len() {
            if
                s
                    .chars()
                    .nth(i - 1)
                    .unwrap() == ')'
            {
                if
                    s
                        .chars()
                        .nth(i - 2)
                        .unwrap() == '('
                {
                    f[i] = f[i - 2] + 2;
                } else if
                    (i as i32) - f[i - 1] - 1 > 0 &&
                    s
                        .chars()
                        .nth(i - (f[i - 1] as usize) - 2)
                        .unwrap() == '('
                {
                    f[i] = f[i - 1] + 2 + f[i - (f[i - 1] as usize) - 2];
                }
                ans = ans.max(f[i]);
            }
        }
        ans
    }
}
impl Solution {
    pub fn longest_valid_parentheses(s: String) -> i32 {
        let mut stack = vec![-1];
        let mut res = 0;
        for i in 0..s.len() {
            if let Some('(') = s.chars().nth(i) {
                stack.push(i as i32);
            } else {
                stack.pop().unwrap();
                if stack.is_empty() {
                    stack.push(i as i32);
                } else {
                    res = std::cmp::max(res, (i as i32) - stack.last().unwrap());
                }
            }
        }
        res
    }
}

...