题意
给定一个括号序列,求其中合法的最长括号序列的长度
思路
很久以前做过一道类似的题,是用区间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) )。
转移方程:
s[i]==) :d[i] = 0;
s[i]==( :
nm=i+1+d[i+1]
- s[nm]==′)′:d[i]=d[i+1]+2 ,且若 nm+1<n : d[i]+=d[nm+1]nm<n
- 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;
}
};