【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();  // 注意,要先 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())

参考

posted @ 2020-05-29 22:50  Flix  阅读(460)  评论(0编辑  收藏  举报