LeetCode 32: Longest Valid Parentheses

本文深入探讨了如何通过使用栈实现和动态规划方法解决给定字符串中寻找最长有效括号子串的问题。详细解释了两种解题策略的核心思路,包括栈操作和递归关系,旨在帮助读者理解和掌握这一经典算法应用。

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

Longest Valid Parentheses

Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring.

For "(()", the longest valid parentheses substring is "()", which has length = 2.

Another example is ")()())", where the longest valid parentheses substring is "()()", which has length = 4.

解题思路

思路一:使用 stack 存储没有匹配的括号的下标。遍历每个字符 s[i]

  • 若栈顶的括号可以匹配当前括号,计算此时的有效匹配长度:如果 stack 大小为 1,那么从 s[0]s[i] 的所有括号都匹配上了,长度为 i+1;否则有效匹配长度仅为 istack.peek()
  • 若栈顶的括号和当前括号不匹配,则把当前括号入栈,作为未匹配的上一个 index

代码如下:

class Solution {
public:
    int longestValidParentheses(string s) {
        stack<int> posStack; // 使用 stack 存储没有匹配的括号的下标
        int len = s.size(), maxLen;
        for (int i = 0; i < len; ++i) {
            if (s[i] == '(') {
                // 遇到 '(' 直接入栈,和栈顶的括号不匹配
                posStack.push(i);
            }
            else {
                if (!posStack.empty() && s[posStack.top()] == '(') {
                    // 栈顶的括号可以匹配当前括号
                    posStack.pop();
                    // posStack.empty() ? i + 1 : i - posStack.top() 计算了当前有效匹配长度
                    maxLen = max(posStack.empty() ? i + 1 : i - posStack.top(), maxLen);
                }
                else {
                    // 栈顶的括号和当前括号不匹配
                    posStack.push(i);
                }
            }
        }
        return maxLen;
    }
};

思路二:使用动态规划(Dynamic Programming)求解。

维护一个长度为s.length()的一维数组dp[]dp[i]表示从s[i]s[s.length() - 1] 包含s[i] 的最长的有效匹配括号子串的长度。则dp[]存在如下的递推关系:

  • dp[s.length()1]=0
  • is.length()20 逆向求 dp[],并记录其最大值。
    • s[i]=(,则在 s 中从 i 开始到 s.length()1 计算 dp[i] 的值:
      • s 中跳过从 i+1 开始的有效括号匹配子串,查看下一个字符,即下标为 j=i+1+dp[i+1] 的元素。若 j 没有越界,并且 s[j]==),则 s[i...j] 为有效括号匹配,dp[i]=dp[i+1]+2
      • 在求出 s[i...j] 的有效匹配长度之后,若 j+1 没有越界,则 dp[i] 的值还要加上从 j+1 开始的最长有效匹配,即 dp[j+1]
    • s[i]==),则 dp[i]=0

代码如下:

class Solution {
public:
    int longestValidParentheses(string s) {
        int len = s.size(), maxLen = 0;

        int dp[len]; // dp[]
        memset(dp, 0, sizeof(dp)); // 初始化为0
        for (int i = len - 2; i >= 0; --i) {
            // 只对左括号处理,右括号在数组中存储为0
            if (s[i] == '(') {
                // 计算与当前左括号匹配的右括号的位置,可能存在也可能不存在
                int j = i + 1 + dp[i+1];
                if (j < len && s[j] == ')') {
                    /* 找到了相匹配的右括号,当前数组中存储的最长长度是它后一
                     * 个位置加2,后一个位置可能存储长度是0。
                     */
                    dp[i] = dp[i+1] + 2;

                    if (j + 1 < len) {
                        /* 是连接两个子匹配的关键步骤。在j的后面可能已经存在连
                         * 续的匹配,要记得加上。dp[j+1]存储了以j+1开始的匹配
                         */
                        dp[i] += dp[j+1];
                    }

                    if (dp[i] > maxLen) maxLen = dp[i]; //更新最长长度
                }
            }
        }
        return maxLen;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值