括号序列问题
括号序列与前缀和
将(
和)
分别看成是
1
1
1和
−
1
-1
−1,得到一个数字序列,对这个数字序列做前缀和,可以通过这个前缀和判断其任意子序列是否合法。
子序列合法等价于 p s u m [ r ] − p s u m [ l − 1 ] = 0 psum[r] - psum[l - 1] = 0 psum[r]−psum[l−1]=0并且 min i = l r p s u m [ i ] − p s u m [ l − 1 ] ≥ 0 \min_{i=l}^r psum[i] - psum[l - 1] \geq 0 mini=lrpsum[i]−psum[l−1]≥0。其后者可以使用RMQ解决。
在一个合法的序列中任意插入一对()
,其序列仍合法,删除也同理。证明:在插入)
势必会插入(
,其)
前一个前缀和即使为
0
0
0,在插入)
后也会为
1
1
1,所有不会出现负的前缀和。此外插入一对()
,对其整体和不改变。
删除任意如()()()()...
的子序列的最小步数等价于最大前缀和。
这个题还可以时候前缀和+贪心的方式进行处理。
我们维护两个变量,一个为 m x mx mx,另一个为 m i mi mi,计算方法如下,遇到‘*’的时候,分别看成左右括号,变量分别加一减一。
for (int i = 0; i < s.size(); i++)
{
if (s[i] == '(')
{
mx++;
mi++;
}
else if (s[i] == ')')
{
mx--;
mi--;
}
else
{
mx++;
mi--;
}
mi = max(0, mi);
if (mx < 0)
return false;
}
我们考虑 m i mi mi为负的时候,考虑撤回一个’*‘使其不让他成为’)’,如果均撤销,那么就让它变成’(’,如果可用’*‘不够用的时候,即’*‘全变为’('也改变不了 m i mi mi为负数的情况,即 m x < 0 mx < 0 mx<0,则返回false。最后查看 m i mi mi是否为0即可。
括号序列和区间DP
括号序列是显然的区间,故可以使用区间DP求解。
例如:
括号序列和栈
括号序列和栈是一对对应的数据结构,其多数问题均可以使用栈解决。
- 合法的括号序列计数:Catalan数列