题目描述
难度分:1400
输入n(1≤n≤105)和n个括号字符串,字符串长度之和≤5×105。
你需要从中选出2m个括号串,两两一对,拼接成m个合法括号字符串。
输出m的最大值。
输入样例1
3
)
()
(
输出样例1
2
输入样例2
2
()
()
输出样例2
4
算法
贪心
每个字符串从左往右遍历,按照括号匹配的思路计算最后剩下的左括号“净含量”left和右括号“净含量”right。观察之后可以发现如下规律:
- 如果left>0和right>0同时成立,这个字符串就应该被抛弃掉,不可能存在能和它匹配出合法括号串的另一个字符串。
- 如果left>0,就把它记录到哈希表lcnt中(lcnt的映射关系为“左括号净含量 → 这个净含量的字符串数目”)。
- 如果right>0,就把它记录到哈希表rcnt中(rcnt的映射关系为“右括号净含量 → 这个净含量的字符串数目”)。
- 如果left=right=0,记录满足这个的字符串数目zcnt,这样的字符串可以两两配对,一共产生[zcnt2]个合法括号串(其中[.]表示对.的向下取整操作)。
接下来就是让左括号“净含量”与右括号“净含量”相等的串进行配对,对于一个在lcnt和rcnt都存在的“净含量”x,它对答案的贡献为min(lcnt[x],rcnt[x]),把这些x的贡献都累加起来就是答案。
复杂度分析
时间复杂度
遍历了n个字符串一次,对于每个字符串,需要遍历它的每个字符,而字符串长度的总和也是O(n)的,因此遍历的时间复杂度为O(n)。
之后要遍历哈希表lcnt,对每个key都要检查其是否也在rcnt中,从而计算最大配对数。在最差情况下每个字符串的左括号净含量都不同,有O(n)级别的key数量,因此遍历的时间复杂度为O(n)。
综上,整个算法的时间复杂度为O(n)。
空间复杂度
开辟了lcnt和rcnt两个哈希表的空间,在最差情况下这两个哈希表会存O(n)级别的键值对,因此算法整体的额外空间复杂度为O(n)。
C++ 代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;
int n;
int main() {
scanf("%d", &n);
int zcnt = 0;
unordered_map<int, int> lcnt, rcnt;
for(int i = 0; i < n; i++) {
string s;
cin >> s;
int left = 0, right = 0;
for(char c: s) {
if(c == '(') {
left++;
}else {
if(left > 0) {
left--;
}else {
right++;
}
}
}
if(left > 0 && right > 0) continue;
if(left > 0) {
lcnt[left]++;
}else if(right > 0) {
rcnt[right]++;
}else {
zcnt++;
}
}
int ans = zcnt>>1;
for(auto&[k, v]: lcnt) {
if(rcnt.find(k) != rcnt.end()) {
ans += min(v, rcnt[k]);
}
}
printf("%d\n", ans);
return 0;
}