小黄的刷题之路(四)——码题集OJ赛题-字符串化简

1. 题目

在这里插入图片描述

样例:

输入:aa(aa)|(aa|(a|aa))aa
输出:4

备注:

测试数据保证括号匹配,且 | 两侧与括号内均不会出现空串。测试数据保证输入的字符串长度不超过 1 0 5 10^5 105


2. 分析思路

2.1 审题和分析

看完题目,我们可以总结出以下重要的几点:

  • 按照特定规则化简字符串,字符串只可能由字母‘a’分隔符‘|’,**括号‘()’**构成
  • 保证输入全部正常,没有空串。不用考虑处理异常输入
  • 这是一个典型的字符串处理问题,一般的做法都需要遍历每个字符,针对不同的情况做不同处理,并且需要用到’ 栈 ’
  • 化简后的字符串只含a,最终的答案就是这个纯a串的长度
2.2 思路

设置一个变量a_cnt来计算纯a串的长度,初始化a_cnt=0。使用容器vector来充当栈和数组

(1)先考虑一种简单的情况:化简字符串 【aa|aaa】

  • 很直观的我们可以知道化简的结果是【aaa】,输出的答案就是3,那么如果要程序来化简,要怎么做呢?
  • 遍历这个字符串,遇到分隔符之前,a_cnt = 2,紧接着遇到了|,这个时候我们可以先把a_cnt = 2压入栈op中重置a_cnt = 0,为了后续知道我们此时遇到了分隔符,入栈一个标识符’-1‘,接着我们继续遍历分隔符右边的部分直到结束,此时a_cnt = 3,遍历结束,发现a_cnt不为0,将其入栈
vector<int>op;
int a_cnt = 0;//对字符a计数
while(cin>>ch)//循环用例,ctrl+Z才能结束
{
    if(ch == 'a')a_cnt++;
    else if(ch == '|')
    {
        op.push_back(a_cnt);//入栈
        op.push_back(-1);//分隔符的标识符为-1
        a_cnt = 0;//置0是为了对分隔符右边重新计数
    }
}
if(a_cnt != 0)op.push_back(a_cnt);
  • 接着我们目光放到这个栈op上,现在op的元素分别是[2 , -1 , 3]
int ans_pre=0;//分隔符左边的长度
int ans=0;//两边中较大的长度
for(int i=0;i<op.size();i++)
{
    op_ch = op[i];
    if(op_ch != -1)ans += op_ch;//不是分隔符 |,而是a_cnt
    else if(op_ch == -1){//是分隔符 |
        ans_pre = max(ans,ans_pre);
        ans = 0;
    }
}
ans = max(ans,ans_pre);
cout<<ans;

所以遍历的过程ans和ans_pre的变化就是:

ans=0, ans_pre=0 ⇒ \Rightarrow ans=2, ans_pre=0(i=0) ⇒ \Rightarrow ans=0, ans_pre=2(i=1) ⇒ \Rightarrow ans=3, ans_pre=2(i=2,for循环结束) ⇒ \Rightarrow ans = 3 , 所以最终答案就是 3

(2)复杂一点的情况无非就是考虑括号,只是需要做个优先级处理

  • 如果遇到 ‘ ( ’ ,前面计算的a_cnt就需要入栈,并重置为0以进行括号内的计数,同时要入栈一个标识符 -2
if(ch == '(')
{
	op.push_back(a_cnt);
	a_cnt = 0;
	op.push_back(-2);//左括号的标识符
}
  • 这中间可能会遇到字符a和分隔符,但最后一定会遇到 ‘ ) ’,在遇到’ ) '前的这一路上,情况不就等同于(1)吗
else if(ch == ')')
{
	op.push_back(a_cnt);
	a_cnt = 0;
	int ans=0,ans_pre=0;
	while(1)
	{
		op_ch = op.back();
		op.pop_back();
		//遇到的是数字
		if(op_ch != -1 && op_ch != -2)ans += op_ch;
		else if(op_ch == -1){//遇到分隔符 |
		ans_pre = max(ans,ans_pre);
		ans = 0;
		}
		else if(op_ch == -2){//遇到'('
		ans = max(ans,ans_pre);
		op.push_back(ans);
		break;
		}
	}
}

最终把代码整合一下


3. 代码实现

3.1 C++代码实现
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
char ch;
int op_ch;
vector<int>op;
int main()
{
    int a_cnt = 0;//对字符a计数
    while(cin>>ch)//循环用例,ctrl+Z才能结束
    {
        if(ch == 'a')a_cnt++;
        else if(ch == '|'){//分隔符
            op.push_back(a_cnt);
            op.push_back(-1);//分隔符的标识符为-1
            a_cnt = 0;
        }
        else if(ch == '('){//左括号
            op.push_back(a_cnt);
            a_cnt = 0;
            op.push_back(-2);//左括号的标识符为-2
        }
        else if(ch == ')')//右括号
        {
            op.push_back(a_cnt);
            a_cnt = 0;//重置,为了新的计数
            int ans=0,ans_pre=0;
            while(1)
            {
            	op_ch = op.back();//取栈顶元素
	            op.pop_back();//出栈
                //遇到的是数字
                if(op_ch != -1 && op_ch != -2)ans += op_ch;
                else if(op_ch == -1){//遇到分隔符 |
                    ans_pre = max(ans,ans_pre);
                    ans = 0;
                }
                else if(op_ch == -2){//遇到'('
                    ans = max(ans,ans_pre);
                    op.push_back(ans);
                    a_cnt = 0;
                    break;
                }
            }
        }
    }
    if(a_cnt != 0)op.push_back(a_cnt);
    int ans_pre=0,ans=0;
    for(int i=0;i<op.size();i++)
    {
        op_ch = op[i];
        if(op_ch != -1)ans += op_ch;//不是分隔符 |
        else if(op_ch == -1){//是分隔符 |
            ans_pre = max(ans,ans_pre);
            ans = 0;
        }
    }
    ans = max(ans,ans_pre);
    cout<<ans;
    return 0;
}
3.2 总结

这道题对于我的难度还是比较大的,最关键的就是能想到下面几点:

  • 使用容器既能作为栈也能作为数组使用
  • 自己由简单到复杂想一个测试用例,思考如何逐步解决这些例子,逐步完善代码逻辑
  • 标识符的使用以及ans和ans_pre变量的使用比较巧妙,可以多积累这样的代码经验

⭐感谢您能看到这里,这是对我莫大的鼓励,如果觉得对你有帮助,不妨关注一下我,后续还有大量的刷题分享哦,让我们一同进步吧!⭐

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值