Leetcode 32 - Longest Valid Parentheses(线性dp)

66 篇文章 0 订阅

题意

给定一个括号序列,求其中合法的最长括号序列的长度

思路

很久以前做过一道类似的题,是用区间dp, O(n3) 的时间复杂度过的,这道题 O(n) 的线性dp就可以了。

状态表示 d[i] ,以元素s[i]作为起点的最长括号序列。

其实我们的括号序列无非就这两种情况的嵌套:()()和(())。根据以上的状态表示我们列出对应的d[]数组:

( ) ( )

4 0 2 0

( ( ) )

4 2 0 0

当我们开始处理s[i]时,若 s[i]==) ,d[i]肯定为0。

关键就是左括号:

首先,我们需要找到需要和当前左括号匹配的那个括号的位置,我们记那个括号的位置是nm(need_to_match),计算可得: nm=i+1+d[i+1]

nm的得出:d[i + 1]为我们的s[i + 1]匹配的括号长度,即从i + 1开始,走过d[i + 1]的序列是已经匹配过的,所以需要和我们s[i]匹配的位置 nm==i+1+d[i+1]

当我们得到nm后,因为s[i] == (,若s[nm] == ),则d[i] = 0。

不然,我们的s[nm] == ),即s[i]和s[nm]是匹配的。

首先,d[i] = d[i + 1] + 2(d[i + 1]为s[i + 1]匹配的括号长度,我们需要在i + 1的基础上叠加上当前匹配的())。

然后,我们还要考虑这样一种情况,就nm + 1之后匹配的长度我们也要叠加上,因为我们d[i]表示的是从i开始的满足条件的括号序列的长度,则i到nm是满足条件的,我们还需要加上nm+1满足条件的那段序列(即可以考虑这样一种情况:(())())。所以此时d[i]还要叠加上d[nm + 1]。(可以参考一道类似的题: HDU1506-Largest Rectangle in a Histogram(dp) )。

转移方程

  1. s[i]==) :d[i] = 0;

  2. s[i]==( :

    nm=i+1+d[i+1]

    1. s[nm]==):d[i]=d[i+1]+2 ,且若 nm+1<n d[i]+=d[nm+1]nm<n
    2. s[nm]==(:d[i]=0nm<n

时间复杂度 O(n)

空间复杂度 O(n)

代码

const int maxn = 100000 + 5;
int d[maxn];

class Solution {
public:
    int longestValidParentheses(string s) {
        memset(d, 0, sizeof(d));
        int n = s.length(), res = 0;
        if (n == 0) return 0;
        d[n - 1] = 0; //init, the last element is 0
        for (int i = n - 2; i >= 0; i--) {
            if (s[i] == ')') d[i] = 0;
            else {
                int nm = i + 1 + d[i + 1]; //the position that current element need to match
                if (nm < n && s[nm] == ')') {
                    d[i] = d[i + 1] + 2;
                    int nxt = nm + 1;
                    if (nxt < n) d[i] += d[nxt];
                }
            }
            res = max(res, d[i]);
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值