16.括号匹配

目录

题目

思路

注意事项

C++完整代码(含详细注释)


题目

Description
在乐学上出了一道给定括号序列,判断其合法性的问题。
括号序列是由左括号“(”和右括号“)”组成的非空序列。对于一个括号序列很容易判定其合法性。比如“()”、“(())()”、“(()())”、“(()(()))”、“()()()”都是合法的,而“)”、“(”、“(()”、“(()))(”都是非法的。
看了一眼题,立刻去饮水机处接了一杯水。
意识到他是在暗示这道题太水了,于是立刻把题改了改,增加了一、、难度。
给定  个括号序列,两两配对,问最多能组成多少对合法括号序列。(每一个括号序列只能在一对中出现)
接完水回来再看了看新题,开始挠头了,快帮帮他!
Input
第一行输入整数   表示有  个括号序列。
接下来  行,每行输入一个只由“(”和”)“构成的字符串  。(字符串长度满足)
所有字符串长度总和满足。
Output
输出一个整数,表示最大的合法括号序列对数。
Hint
第一组用例可以组成2对合法括号序列,分别是“((   )())”、“(   )”。


思路

  1. 定义一个函数simplify,用于简化括号序列。函数接受一个字符串s作为参数,用于存放简化后的序列。同时,定义一个计数器count,用于判断序列简化后是否为空。
  2. 遍历括号序列,对每个字符进行判断: a. 如果是左括号,则需要一个右括号将其抵消,因此将右括号入栈,并将计数器count加1。 b. 如果是右括号,先判断栈顶是否是右括号。如果是,则说明前面有左括号可以与其抵消,将计数器count减1,并将栈顶的右括号出栈。如果不是,则将其需要的左括号入栈,并将计数器count加1。
  3. 如果计数器count为0,说明括号序列本身就是完美匹配的,将字符串s置为空字符串。
  4. 将简化后所需要的括号序列返回。
  5. 在主函数中,首先读入输入的数据,包括楼房的数量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;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

榆榆欸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值