leetcode32. 最长有效括号

该博客介绍了如何解决LeetCode32题——最长有效括号问题。通过分析示例和思考过程,提出暴力法和动态规划两种解法。重点讲解动态规划的思路,创建dp数组记录以每个字符结尾的最大有效括号长度,并阐述动态规划解决问题的核心逻辑。文章还提供了相关参考资料链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://leetcode-cn.com/problems/longest-valid-parentheses/

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

示例 1:

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

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

输入:s = ""
输出:0
 

提示:

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

拿到题,这种对称的问题,一般首先想到的都是栈。但是我不一开始就用栈来解决,假设我们一开始没有想法怎么解决。我们首先按照从简到难的顺序一一解决。

思考:

文中数最长有效字符串,我们想到要考虑有哪些情形

比较个数 

符号(比符号)多

(

(()

符号)比符号(多

 )       

())

符号(和符号)相同

()

暴力法:

以每个字符为首字符,寻找其最大的有效长度,(()(c

# 暴力破解法
# 遍历字符串中的每一个字符,以每个字符开头,找到其最大的合法字符。
# 若符号(的个数大于符号)的个数,则可能还是有效的,继续处理
# 若(的个数等于)则统计最大值。
# "(()"  1,以第一个开头未找到合法字符,第二个才找到最大的合法数2
# ()))())())(())
# 遍历数据
# 若)丢弃,跳到下一个
# 若(,继续下面的操作,进行后续遍历。
# 1,统计左右的个数,l,r
# 2,( l+1,) r+1
# 3,若l>r,继续,?,若r=l,则max(2r,maxLen)
# l<r 结束,此字符开头的合法字符串结束。
def brute_search(s: str):
    max_len = 0
    s_len = len(s)
    for i in range(s_len):
        if s[i] == "(":
            l, r = 0, 0
            for j in range(i, s_len):
                if s[j] == "(":
                    l += 1
                if s[j] == ")":
                    r = r + 1
                if l == r:
                    max_len = max(2 * r, max_len)
                if l < r:
                    break
    return max_len


if __name__ == "__main__":
    s = "()(()"
    ans = brute_search(s)
    # ans = brute_force(s)
    print(ans)

2,栈解决法,记录下标。思维独特,想不出来。

    def longestValidParentheses(self, s: str) -> int:
        stack: int = [-1, ]
        max_len = 0
        s_len = len(s)
        for i in range(s_len):
            if s[i] == "(":
                stack.append(i)
            elif len(stack) > 1:
                    stack.pop()
                    max_len = max(i - stack[-1], max_len)
            else:
                 stack[-1] = i
        return max_len  

3,动态规划

动态规划最朴素的思路就是拆分问题,将大问题拆分成小问题。但是和分治算法不同的是,动态规划更加关注子问题和原问题之间的逻辑联系,而分治算法可能更加侧重拆分。并且分治算法的拆分通常是基于数据和问题规模的,而动态规划则不然,更加侧重逻辑。除此之外,动态规划也非常注重模式的构造。

我们最经常干的一件事情就是创建一个叫做dp的数组,它来记录每一个位置能够达到的最佳结果。比如在这题当中,最佳结果就是最长匹配的括号串。所以dp[i]就记录以s[i]结尾的字符串能够构成的最长的匹配串的长度。

"""
遍历s,如果遇到s[i]是左括号,则以左括号结尾的最长有效子串一定是零,
直接跳过;如果遇到右括号,则需要根据s[i-1]的情况进行判断。

如果s[i-1]是左括号,说明s[i-1]与s[i]正好凑成一对,dp[i]直接在dp[i-2]的基础上加2即可。

如果s[i-1]是右括号,则需要寻找一下,与当前右括号s[i]配对的左括号应该在哪里,
我们把这个左括号应该在的位置定义为j,有j = i - 1 - dp[i - 1],
dp[i-1]即以s[i-1]结尾的有效括号的最大长度,
相当于i位置和j位置的左右括号把dp[i-1]长度的有效子串夹在中间。
这时就需要看了,j位置到底是不是左括号,
如果是左括号,则可以将以j-1结尾的最长有效子串,以i-1结尾的最长有效子串,
以及i和j位置的左右括号一起合并成一个大的有效子串,
长度一共是dp[j-1]+1+dp[i-1]+1,相反,
如果j-1位置处不是左括号,说明当前右括号没有与之匹配的左括号,直接跳过次轮循环即可。
"""
def long_parentheses_dy(s: str):
    s_len = len(s)
    d = s_len * [0]
    for i in range(1, s_len):
        if s[i] == ")":
            if s[i - 1] == "(":
                d[i] = 2 + (d[i - 2] if i > 1 else 0)
            elif i - d[i - 1] - 1 >= 0 and s[i - d[i - 1] - 1] == "(":
                d[i] = d[i - 1] + 2 + (d[i - d[i - 1] - 1 - 1] if i-d[i-1]-2>=0 else 0)
    return max(d + [0])  # max([]),[0]

和栈方法大同小异,都是利用下标位置去计算最大的长度

理解动态思想

参考:https://cloud.tencent.com/developer/article/1594863

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值