CF——E. Replace With the Previous, Minimize

题目链接

题目大意:给定一个字符串,问在执行k次操作后字典序最小的字符串是什么?
一次操作的定义:对于任意一个字符串中的字母s,将字符串内所有为s的字母转换为s-1
即b可以转换为a,c可以转换为b,……,z可以转换为y。

基本思路

  1. 因为是要将字符串转换为字典序最小的字符串,因此执行的操作优先考虑下标较小的字符
  2. 对于操作的理解:对于某个字母m,如果要将其转换为a,则执行m-a次操作,我们可以将整个字符串中的所有[a,m]区间内的字母都转换为a。(可以手动从m开始模拟,理解为逐步翻牌的感觉)
  3. 转换为代码思路:
    1. 存储一个mx值来记录当前可以直接转换为a的右边界,即遍历到当前位置的时候,整个字符串中大小在[a,mx]区间内的字母都可以通过最多mx次操作转换为a
    2. 如果当前字母转换为a的需要的操作数<=k,则直接更新mx值
    3. 如果当前字母转换为a需要的操作数>k,则该字母最多只能进行(k-mx)次操作;如果当前字母为s,则字符串中[s-(k-mx),s]区间内的字母都可以转换为s-(k-mx),转换为尽可能中最小的字母。

上代码~

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;
    cin>>T;
    for(int t=0; t<T; t++)
    {
        int n,k;
        cin>>n>>k;
        string s;
        cin>>s;
        int mx=0;
        /*将字符串通过操作变成字典序最小的字符串,
        因此贪心的优先级为对坐标小的字母执行尽可能多又不浪费的操作*/
        //在操作过程中,mx记录字符串中通过操作可以变成a的最大右边界;即[0,mx]+'a'的字符都可以变成'a'。
        for(int i=0; i<s.size(); i++)
        {
            int opnumToa=s[i]-'a';
            if(opnumToa<=k)
                //如果s[i]转换为'a'的次数<k, 表示['a',s[i]]间的所有字母都可以通过s[i]-'a'次转换为'a';
                mx=max(mx,opnumToa);
            else
                //如果该字母变成a的操作次数超过k,表示无法在k次操作内转换为a
            {
                char minLetter=s[i]-(k-mx);
                char maxLetter=s[i];
                //之前的字母变成a已经花费了mx次操作,因此这个字母最多只能花费k-mx次操作
                //因此即使用(k-mx)操作使[minLetter,maxLetter]区间内的字母都变成minLetter
                for(int j=0; j<s.size(); j++)
                {
                    if(minLetter<=s[j]&&s[j]<=maxLetter)s[j]=minLetter;
                }
                break;
            }
        }
        //最后将[a,mx]区间内的所有字母转换为a
        for(int i=0; i<s.size(); i++)
        {
            int indx=s[i]-'a';
            if(indx<=mx)s[i]='a';
        }
        cout<<s<<endl;
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值