目录
题目
Description
在乐学上出了一道给定括号序列,判断其合法性的问题。
括号序列是由左括号“(”和右括号“)”组成的非空序列。对于一个括号序列很容易判定其合法性。比如“()”、“(())()”、“(()())”、“(()(()))”、“()()()”都是合法的,而“)”、“(”、“(()”、“(()))(”都是非法的。
看了一眼题,立刻去饮水机处接了一杯水。
意识到他是在暗示这道题太水了,于是立刻把题改了改,增加了一、、难度。
给定 个括号序列,两两配对,问最多能组成多少对合法括号序列。(每一个括号序列只能在一对中出现)
接完水回来再看了看新题,开始挠头了,快帮帮他!
Input
第一行输入整数 表示有 个括号序列。
接下来 行,每行输入一个只由“(”和”)“构成的字符串 。(字符串长度满足)
所有字符串长度总和满足。
Output
输出一个整数,表示最大的合法括号序列对数。
Hint
第一组用例可以组成2对合法括号序列,分别是“(( )())”、“( )”。
思路
- 定义一个函数simplify,用于简化括号序列。函数接受一个字符串s作为参数,用于存放简化后的序列。同时,定义一个计数器count,用于判断序列简化后是否为空。
- 遍历括号序列,对每个字符进行判断: a. 如果是左括号,则需要一个右括号将其抵消,因此将右括号入栈,并将计数器count加1。 b. 如果是右括号,先判断栈顶是否是右括号。如果是,则说明前面有左括号可以与其抵消,将计数器count减1,并将栈顶的右括号出栈。如果不是,则将其需要的左括号入栈,并将计数器count加1。
- 如果计数器count为0,说明括号序列本身就是完美匹配的,将字符串s置为空字符串。
- 将简化后所需要的括号序列返回。
- 在主函数中,首先读入输入的数据,包括楼房的数量n、每个楼房的颜色和高度。然后定义两个数组l和r,分别用于记录需要左括号和右括号的序列个数。同时,定义一个变量valid,用于记录本身就完美匹配的括号序列的个数。
接下来,遍历括号序列,对每个序列进行简化,并统计需要的左括号和右括号的个数。如果序列为空,说明其本身完美匹配,将valid加1。否则,统计左括号和右括号的个数,并将其加入对应的数组l和r中。
然后,遍历需要左括号和右括号的序列个数的数组,计算需要的括号序列的个数。由于一个序列只能使用一次,所以取数组l和r中的较小值,并将其累加到变量sum中。
最后,将valid除以2,并将结果加到sum中,得到最终的结果,输出sum。
注意事项
需要注意的是,
- 简化括号序列的函数中,使用了一个字符串simplified作为栈,用于存放简化后的序列。
- 同时,使用一个count变量判断序列简化后是否为空。
- 在遍历括号序列时,需要注意记录左括号和右括号的个数,并根据个数进行相应的处理。
- 遍历需要左括号和右括号的数组时,需要注意取两者中的较小值进行累加。
C++完整代码(含详细注释)
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <climits>
using namespace std;
//简化括号序列得到所需要括号序列的函数
void simplify(string& s) {
string simplified;//暂时存放简化的序列,这里的字符串相当与一个栈
int count = 0;//用于判断序列简化后是否为空
for (char ch : s) {
if (ch == '(') {//如果是左括号,说明需要一个右括号将其抵消
simplified.push_back(')');//右括号入栈
count++;
}
else if (ch == ')') {//如果是右括号,则先判断栈顶是否是右括号
if (count > 0 && simplified.back() == ')') {//如果是,则说明前面有左括号可以与其抵消
count--;
simplified.pop_back();
}
else {//如果不是,将其需要的左括号入栈
simplified.push_back('(');
count++;
}
}
}
if (count == 0) s = "";//如果栈为空,说明这个括号序列本身就是完美匹配的
s = simplified;//将简化后所需要的括号序列返回
}
int main() {
int n;
cin >> n;
vector<string> vec(n);
vector<int> l(5e5 + 1, 0), r(5e5 + 1, 0);//分别记录需要左括号或右括号的序列个数,下标既是需要的括号个数
int valid = 0;//记录本身就完美匹配的括号序列
for (int i = 0; i < n; i++) {//遍历括号序列
int left = 0, right = 0;//记录左括号和右括号数
cin >> vec[i];
simplify(vec[i]);
if (vec[i] == "") valid++;//如果为空,说明其本身完美匹配
else {//否则,记录其所需要的左(或右)括号数
for (char ch : vec[i]) {
if (ch == '(') {
left++;
}
else {
right++;
}
}
//左右括号都需要的序列无法和任何别的序列组合
//我们需要分别记录需要左括号和右括号序列的个数
if (left && !right) {
l[left]++;
}
else if (!left && right) {
r[right]++;
}
}
}
int sum = 0;
for (int j = 0; j <= 5e5; j++) {//遍历需要左(或右)括号数的数组
sum += min(r[j], l[j]);//取两者中的较小值,因为一个序列只能用一次
}
sum += valid / 2;//两个完美匹配的序列放在一起仍然完美匹配,但要记得除2
cout << sum << endl;
return 0;
}