中等难度
给你一个字符串
s
和一个整数k
。定义函数
distance(s1, s2)
,用于衡量两个长度为n
的字符串s1
和s2
之间的距离,即:
- 字符
'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;
}
};