LintCode 193: Longest Valid Parentheses (Stack 和 DP)

  1. Longest Valid Parentheses

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

Example
Example 1:

Input: “(()”
Output: 2
Explanation: The longest valid parentheses substring is “()”
Example 2:

Input: “)()())”
Output: 4
Explanation: The longest valid parentheses substring is “()()”

解法1:stack
这题比单纯判断字符串是否合法要复杂一些。一开始我的思路就是遇到’(’就压栈,遇到’)'就出栈,同时count+2。但看看input=")(()(()"就知道了,这个方法会返回4(因为遇到2个()),但实际答案为2,因为这2个()没有连在一起。
参考了网上的答案。这题要注意记录一个合法序列开始时候的position!

  1. 当遇到’('时,压栈;
  2. 当遇到’)'时,
    2.1) 如果栈为空,那么说明此时input已经不合法了,startPos从下一个位子开始算。
    2.2) 如果栈非空,那么st.pop()。
    若此时栈空了,说明此时从上个startPos到现在都合法(即从上次栈空到这次栈空之间都合法),记录maxCount=max(maxCount, i - startPos + 1)。
    若此时栈仍然为非空,说明从st.top()的下一个位置开始到i都合法,记录maxCount=max(maxCount, i - st.top())。//i-st.top()即i-(st.top()+1)+1
    注意这里一定要用i-st.top()而不是i-st.old_top + 1。//old_top即st.pop()出来的那个位置。
    比如说input = “)(()()()”,那么最后i=7,st.pop(),stack仍然非空,st.top()=1,说明从i=2的位置就开始合法了,maxCount=i-1=6,即”()()()“的长度。
    如果我们用i-st.old_top()+1=7-6+1=2就不对了,此时只记录了最后一个()的长度。
    注意:stack st; 这里压栈的是index, 不要用stack st;
    代码如下:
class Solution {
public:
    /**
     * @param s: a string
     * @return: return a integer
     */
    int longestValidParentheses(string &s) {
        int n = s.size();
        stack<int> st; //positions
        int startPos = 0;
        int maxCount = 0;
        for (int i = 0; i < n; ++i) {
            if (s[i] == '(') st.push(i);
            else if (s[i] == ')') {
                if (!st.empty()) {
                    st.pop();
                    if (st.empty()) {
                        maxCount = max(maxCount, i - startPos + 1);
                    } else {
                        maxCount = max(maxCount, i - st.top());
                    }
                } else {
                    // a new valid period starts from i + 1
                    if (i < n - 1) startPos = i + 1; 
                }
            }
        }
        
        return maxCount;
    }
};

解法2:DP。
从后往前扫描,若某个s[i]为左括号,则dp[i+1]为s[i+1]开头的最长合法括号串长度,我们看 j = i + dp[i + 1] + 1是不是右括号,若是,dp[i]=dp[i+1]+2。这里2就是加了左右2个括号长度增2。注意,我们还要考虑dp[j+1],其为s[j+1]开头的最长合法括号串长度。因为之前还没有扫描到s[i],所以s[j]没有左括号和它匹配,所以左右2段最长合法括号串(长度分别为dp[i+1]和dp[j+1])被分开了,这里要把它们加起来。

当然这个从前往后扫描也可以,当s[i]=')‘时,找前面的’('跟它匹配即可。

class Solution {
public:
    /**
     * @param s: a string
     * @return: return a integer
     */
    int longestValidParentheses(string &s) {
        int n = s.size();
        if (n <= 1) return 0;
        
        int res = 0;
        vector<int> dp(n, 0);
        
        for (int i = n - 2; i >= 0; --i) {
            if (s[i] == '(') {
                int j = i + dp[i + 1] + 1;
                if (s[j] == ')') {
                    dp[i] = dp[i + 1] + 2;
                    if (j + 1 < n)  dp[i] += dp[j + 1];
                }
                
                res = max(res, dp[i]);
            }
        }
        
        return res;
    }
};

代码同步在
https://github.com/luqian2017/Algorithm

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值