[Leetcode] 32. 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.

思路

        这种求极值的问题很多情况下都可以采用动态规划加以解决,本题也不例外。可是对dp的不同定义却可以导致非常不同的时间复杂度。这里提供几种不同的思路:

1、二维动态规划:dp[i][j]表示从i到j之间的字符串是否可以构成合法的括弧对,则递推公式为:

        1)如果dp[i+1][j-1] == true,并且s[i] == '(' && s[j] == ')',则dp[i][j] = true;

        2)如果存在i < k < j,使得dp[i][k] == true && dp[k+1][j] == true,则dp[i][j] = true。

        如果dp[i][j]为true,则可以更新当前得到的最长合法括号长度。可惜这种思路的时间复杂度高达O(n^3),空间复杂度为O(n^2),无法通过Leetcode上面的大数据。

2、一维动态规划+栈:利用栈来保证左括弧的数目不小于右括弧的数目(这是括弧对合法的必要条件)并且记录当前左括弧的位置。定义dp[i + 1]表示以i 为结尾的最长合法括弧对的长度。根据左右括弧匹配的性质,思路为:

        1)如果字符串中当前字符为‘(’,则将其位置入栈,代表这个位置需要有一个匹配的右括弧;

        2)如果字符串中当前字符为')',则检查栈:

              a)如果此时栈为空,说明当前段的字符串是不合法的;

              b)如果此时栈不为空,则说明当前的右括弧可以被匹配,并且dp[i+1] = (i - j + 1) + dp[j]。其中(i - j + 1)表示从当前字符到栈顶元素的长度,而dp[j]表示栈顶元素之前的合法子字符串的长度。该思路的时间复杂度为O(n),空间复杂度为O(n)。

3、一维动态规划:仔细推敲2的思路,发现实际上对于dp[i+1]而言,通过dp[i]可以推导出能够和s[i] == ')' 匹配的左括弧的索引值为(i - dp[i] - 1)。那么我们就不再需要开辟栈空间了,而是可以直接推导出dp[i+1]和dp[i]之间的递推关系:dp[i + 1] = dp[i - dp[i] - 1] + dp[i] + 2。该算法的时间和空间复杂度同2。

4、栈:事实上')'也是可以作为分界符入栈的。如果当前字符为')',则试图在栈中寻找和它匹配的'('的左括弧。如果找到相对应的左括弧,则首先弹栈(为什么要先弹栈? 考虑()()的情况),然后可以知道以‘)’结尾的合法括弧对的长度为st.empty() ? i + 1 : i - st.top()。而不以该')'结尾的合法最长合法括弧对的长度为在此前已经被记录下来了,所以此时只需要更新其值即可。一旦无法找到和当前')'匹配的左括弧,则将该')'入栈作为分界符,使得后来的右括弧无法再与当前栈中非栈顶的左括弧相匹配。这个思路确实很精妙,虽然 理论上时间复杂度和空间复杂度仍然为O(n),但事实上在大多数情况下空间复杂度会远小于O(n)。

代码

一维动态规划+栈:

class Solution {
public:
    int longestValidParentheses(string s) 
    {
        if(s.size() == 0) 
            return 0;  
        stack<int> st;  
        vector<int> dp(s.size() + 1, 0);
        int ret = 0, len= 0;  
        for(int i = 0; i < s.size(); i++)  
        {  
            if(s[i] == '(') 
            {
                st.push(i);  
            }
            else  
            {  
                if(!st.empty())
                {
                    dp[i + 1] = (i - st.top() + 1) + dp[st.top()];  
                    st.pop();  
                    ret = max(dp[i + 1], ret);  
                }
            }  
        }  
        return ret;  
    }
};
一维动态规划:

class Solution {
public:
    int longestValidParentheses(string s) 
    {
        int ret = 0;
        // dp[i] means the length of the longest valid parenthese that ends with s[i]
        vector<int> dp(s.size() + 1, 0);  
        for(int i = 1; i < s.size(); i++)  
        {  
            if(s[i]=='(') 
                continue;  
            // now we know s[i] == ')'
            // (i - dp[i] - 1) is the index of the '(' that will match with s[i]
            if(i - dp[i] - 1 >= 0 && s[i - dp[i] - 1] =='(')   
                dp[i + 1] = dp[i - dp[i] - 1] + dp[i] + 2;  
            ret = max(ret, dp[i + 1]);  
        }  
        return ret;  
    }
};
栈:

class Solution {
public:
    int longestValidParentheses(string s) 
    {
        int ret = 0;  
        stack<int> st;  
        for(int i = 0; i < s.size(); i++)  
        {  
            if(s[i]=='(') 
            {
                st.push(i); 
            }
            else    // s[i] == ')'
            {
                if(!st.empty() && s[st.top()]=='(')
                {
                    st.pop();  
                    ret = max(st.empty() ? i + 1 : i - st.top(), ret);
                }
                else
                {
                    st.push(i);
                }
            }
        }  
        return ret;  
    }
};




内容概要:本文系统介绍了算术优化算法(AOA)的基本原理、核心思想及Python实现方法,并通过图像分割的实际案例展示了其应用价值。AOA是一种基于种群的元启发式算法,其核心思想来源于四则运算,利用乘除运算进行全局勘探,加减运算进行局部开发,通过数学优化器加速函数(MOA)和数学优化概率(MOP)动态控制搜索过程,在全局探索与局部开发之间实现平衡。文章详细解析了算法的初始化、勘探与开发阶段的更新策略,并提供了完整的Python代码实现,结合Rastrigin函数进行测试验证。进一步地,以Flask框架搭建前后端分离系统,将AOA应用于图像分割任务,展示了其在实际工程中的可行性与高效性。最后,通过收敛速度、寻优精度等指标评估算法性能,并提出自适应参数调整、模型优化和并行计算等改进策略。; 适合人群:具备一定Python编程基础和优化算法基础知识的高校学生、科研人员及工程技术人员,尤其适合从事人工智能、图像处理、智能优化等领域的从业者;; 使用场景及目标:①理解元启发式算法的设计思想与实现机制;②掌握AOA在函数优化、图像分割等实际问题中的建模与求解方法;③学习如何将优化算法集成到Web系统中实现工程化应用;④为算法性能评估与改进提供实践参考; 阅读建议:建议读者结合代码逐行调试,深入理解算法流程中MOA与MOP的作用机制,尝试在不同测试函数上运行算法以观察性能差异,并可进一步扩展图像分割模块,引入更复杂的预处理或后处理技术以提升分割效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值