3106.满足距离约束且字典序最小的字符串

目标

给你一个字符串 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" 。

说明:

  • 1 <= s.length <= 100
  • 0 <= k <= 2000
  • s 只包含小写英文字母。

思路

定义两个由 a - z 组成的长度相等字符串之间的距离为相应位置上字母的最小距离,比如 az 的最小距离为1,ao 之间的距离为12,而非14,an 的距离为13,即距离的最大值为13。因此两字符相减 diff 如果大于13,应取 26 - diff

a b c d e f g h i j k l m

n o p q r s t u v w x y z

现在给定k表示字符串距离,需要我们找出与给定字符串距离为k的字典序最小的字符串。所谓字典序,先取第一个字符比较它在字母表中的排序,如果相等则比较下一个。

因此我们可以遍历给定的字符串的每一个字符,在距离范围内优先将其改为 a,如果距离还有多余,则继续改下一个字母,如果距离不够直接向下取剩余距离的字符。由于字母是首尾相接的,需要考虑是从哪边计算距离最短。第一行从前计算,第二行从后计算,或者两者都计算,比较大小决定如何处理。

代码

/**
 * @date 2024-07-27 22:22
 */
public class GetSmallestString3106 {

    public String getSmallestString(String s, int k) {
        char[] chars = s.toCharArray();
        int n = s.length();
        int i = 0;
        while (k > 0 && i < n) {
            char c = chars[i];
            int dist = Math.min('z' - c + 1, c - 'a');
            if (k < dist) {
                chars[i] = (char) (c - k);
                break;
            }
            chars[i] = 'a';
            k -= dist;
            i++;
        }

        return new String(chars);
    }

}

性能