力扣每日一题 满足距离约束且字典序最小的字符串(贪心)

 中等难度      

给你一个字符串 s 和一个整数 k

定义函数 distance(s1, s2) ,用于衡量两个长度为 n 的字符串 s1s2 之间的距离,即:

  • 字符 'a''z'循环 顺序排列,对于区间 [0, n - 1] 中的 i ,计算所有「 s1[i]s2[i] 之间 最小距离」的

例如,distance("ab", "cd") == 4 ,且 distance("a", "z") == 1

你可以对字符串 s 执行 任意次 操作。在每次操作中,可以将 s 中的一个字母 改变 任意 其他小写英文字母。

返回一个字符串,表示在执行一些操作后你可以得到的 字典序最小 的字符串 t ,且满足 distance(s, t) <= k

示例 1:

输入:s = "zbbz", k = 3
输出:"aaaz"
解释:在这个例子中,可以执行以下操作:
将 s[0] 改为 'a' ,s 变为 "abbz" 。
将 s[1] 改为 'a' ,s 变为 "aabz" 。
将 s[2] 改为 'a' ,s 变为 "aaaz" 。
"zbbz" 和 "aaaz" 之间的距离等于 k = 3 。
可以证明 "aaaz" 是在任意次操作后能够得到的字典序最小的字符串。
因此,答案是 "aaaz" 。

示例 2:

输入:s = "xaxcd", k = 4
输出:"aawcd"
解释:在这个例子中,可以执行以下操作:
将 s[0] 改为 'a' ,s 变为 "aaxcd" 。
将 s[2] 改为 'w' ,s 变为 "aawcd" 。
"xaxcd" 和 "aawcd" 之间的距离等于 k = 4 。
可以证明 "aawcd" 是在任意次操作后能够得到的字典序最小的字符串。
因此,答案是 "aawcd" 。

示例 3:

输入:s = "lol", k = 0
输出:"lol"
解释:在这个例子中,k = 0,更改任何字符都会使得距离大于 0 。
因此,答案是 "lol" 。

 

思路

首先简述一下题目要求,要我们构造出另一个字典序最小的字符串,我们可以随意对原字符串中的字母进行替换,只要满足相同下标下的字母距离和小于等于k即可,注意这个距离是把字母a到z围成一圈来计算的(和钟表的时间排列类似,距离取较小值),首先题目告诉我们可以进行任意次替换,直接考虑贪心,要求字典序最小,就将原字母尽可能的替换成字母a,同时计算替换后距离增加多少,不要超过k,如果剩余距离无法替换成字母a就尽可能的向字典序更小的字母进行替换

解题过程

要求符合题目要求的最小字典序字符串,我们从头开始遍历字符串,设一个变量累计花费的距离,计算当前字符距离字母a的距离,由于是一个环,我们需要取向左抵达a的距离和向右抵达a的距离的较小值作为消耗的距离,即min(s[i]-'a','z'-s[i]+1),同时判断加上这个距离后是否超过k,如果没超过我们就直接替换成字母a,同时累计到花费中去,如果d当前字母无法替换成a,那么就消耗所有剩余距离替换成距离a较近的字母,然后就可以结束循环退出了。

复杂度

  • 时间复杂度: O(n)
  • 空间复杂度: O(1) //我们直接对原字符串进行操作即可
  • 代码如下
class Solution {
public:
    string getSmallestString(string s, int k) {
        int cnt=0;

        for(int i=0;i<s.size();i++)
        {
            if(cnt<k)
            {
                int len=min(s[i]-'a','z'-s[i]+1);
                if(cnt+len<=k)
                {
                    s[i]='a';
                    cnt+=len;
                }
                else
                {
                    s[i]=s[i]-(k-cnt);
                    cnt=k;
                }
                    
            }
            else
                break;

        }

        return s;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值