zoukankan      html  css  js  c++  java
  • 【LeetCode-动态规划/栈】最长有效括号

    题目描述

    给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。
    示例:

    输入: "(()"
    输出: 2
    解释: 最长有效括号子串为 "()"
    
    输入: ")()())"
    输出: 4
    解释: 最长有效括号子串为 "()()"
    

    题目链接: https://leetcode-cn.com/problems/longest-valid-parentheses/

    思路1

    使用和有效括号类似的方法。使用一个栈来存储元素的下标:

    • 如果当前栈为空或者当前字符 s[i] = '(' 或者栈顶元素为 ')' ,则将当前元素的下标 i 入栈;
    • 否则,弹出栈顶元素:
      • 如果栈不空,则比较当前的最长括号长度和 i-stack.top() 之间的大小,根据大小情况更新;
      • 否则,如果栈空,则比较当前的最长括号长度和 i-(-1) 之间的大小(例如,输入的字符串为"()"),根据大小情况更新;

    代码如下:

    class Solution {
    public:
        int longestValidParentheses(string s) {
            if(s.empty()) return 0;
    
            stack<int> st; // 存储下标
            int ans = 0;
            for(int i=0; i<s.size(); i++){
                if(st.empty() || s[st.top()]==')' || s[i]=='(') st.push(i);
                else{
                    st.pop();
                    int t = st.empty()? -1:st.top();
                    ans = max(ans, i-t);
                }
            }
            return ans;
        }
    };
    
    • 时间复杂度:O(n)
    • 空间复杂度:O(n)

    该方法参考了这篇题解

    思路2

    使用动态规划。

    • 状态定义:dp[i] 表示前 i 个字符中最长包含有效括号的子串的长度;
    • 状态转移:
      • 如果 s[i]=='(',则说明 i 是新括号开始的位置,所以 dp[i]=0;
      • 如果 s[i]==')':
        • 如果 s[i-1]=='(',说明找到了一个括号(),则 dp[i] = dp[i-2] + 2;注意这里的 i-1 和 i-2 都不能超数组范围,如果超过范围,则 dp[i]=0;

        • 如果 s[i-1]==')',则要判断 s[i-dp[i]-1] 是否是'(',如果是的话,说明我们碰到了类似(((...)))的情况,此时 dp[i] = dp[i-1] + 2;因为字符串可能是()(((...)))这样的情况
          ,所以要加上 dp[i-dp[i-1]-2]。所以,dp[i] = dp[i-1] + 2 + dp[i-dp[i]-2]。注意,这里的数组下标都不能超过数组范围,如果 i-dp[i]-1 超过了数组范围,则 dp[i]=0;如果 i-dp[i]-2 超过了范围,则 dp[i] = dp[i-1] + 2。

    这两幅图来自这篇题解
    代码如下:

    class Solution {
    public:
        int longestValidParentheses(string s) {
            if(s.empty()) return 0;
    
            int maxLen = -1;
            vector<int> dp(s.length(), 0);
            for(int i=0; i<s.length(); i++){
                if(s[i]=='(') dp[i] = 0;
                else if(s[i]==')'){
                    if(i==0) dp[i] = 0;
                    else if(s[i-1]=='(') dp[i] = (i>=2? dp[i-2]:0) + 2;
                    else if(s[i-1]==')'){
                        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] + 2 + dp[i-dp[i-1]-2];
                            else dp[i] = dp[i-1]+2;
                        }
                        else dp[i] = 0;
                    }
                }
                maxLen = max(maxLen, dp[i]);
            }
            return maxLen;
        }
    };
    
    • 时间复杂度:O(s.length())
    • 空间复杂度:O(s.length())

    思路3

    使用栈来做,栈用来存储下标。

    • 将 -1 入栈;
    • 遍历 s:
      • 如果 s[i]=='(',则将下标 i 入栈;
      • 如果 s[i]==')',则将栈顶元素出栈:
        • 如果栈为空,将 i 入栈;
        • 否则,计算 i-s.top(),并和当前的最大长度做比较,根据大小情况更新当前的最大长度。

    代码如下:

    class Solution {
    public:
        int longestValidParentheses(string s) {
            if(s.empty()) return 0;
    
            int maxLen = 0;
            stack<int> stk;
            stk.push(-1);
            for(int i=0; i<s.length(); i++){
                if(s[i]=='(') stk.push(i);
                else if(s[i]==')'){
                    stk.pop();
                    if(stk.empty()) stk.push(i);
                    else{
                        maxLen = max(i-stk.top(), maxLen);
                    }
                }
            }
            return maxLen;
        }
    };
    
    • 时间复杂度:O(s.length())
    • 空间复杂度:O(s.length())
  • 相关阅读:
    [Clr via C#读书笔记]Cp18 定制Attribute
    [Clr via C#读书笔记]Cp16数组
    [Clr via C#读书笔记]Cp17委托
    [Clr via C#读书笔记]Cp15枚举和位标识
    [Clr via C#读书笔记]Cp14字符字符串和文本处理
    [Clr via C#读书笔记]Cp13接口
    [Clr via C#读书笔记]Cp12泛型
    [Clr via C#读书笔记]Cp11事件
    [Clr via C#读书笔记]Cp10属性
    【程序员面试金典】面试题 02.06. 回文链表
  • 原文地址:https://www.cnblogs.com/flix/p/12989967.html
Copyright © 2011-2022 走看看