题目解析
本文主要讲解一道来自豆包 MarsCode AI 刷题平台的题目“字典序最小的01字符串”,题目要求我们通过最多 k 次相邻字符交换操作,使得一个由 0 和 1 组成的字符串字典序最小化。
题目描述
小U拥有一个由0和1组成的字符串,她可以进行最多 k 次操作,每次操作可以交换相邻的两个字符。目标是通过这些操作,使得最终得到的字符串字典序最小。
输入与输出
输入:一个整数 n 表示字符串长度,一个整数 k 表示最多可以进行的操作数,字符串 s 由 0 和 1 组成。
输出:字典序最小的字符串。
样例
- 输入:
n = 5, k = 2, s = "01010"
输出:"00101" - 输入:
n = 7, k = 3, s = "1101001"
输出:"0110101" - 输入:
n = 4, k = 1, s = "1001"
输出:"0101"
关键思路
为解决这个问题,我们需要在 k 次相邻交换操作的限制下,尽可能多地将 0 移动到字符串的最前面,从而使字符串字典序最小。为了实现这一目标,可以采用如下步骤:
- 贪心策略:从左向右遍历字符串,当遇到字符
0时,尽可能将它往前移动。 - 计算所需交换次数:对于每个
0,计算将它移动到前面所需的最少交换次数。假设0在索引i处,则需要与它前面的1进行i - j次交换操作。 - 更新操作数:每次成功交换后,减少
k中相应的交换次数,直到k次操作耗尽或者字符串无法再做进一步优化。
代码实现
以下是实现上述思路的 Java 代码:
public class Main {
public static String solution(int n, int k, String s) {
char[] chars = s.toCharArray();
for (int i = 0; i < n && k > 0; i++) {
// 如果当前字符是 '1',跳过
if (chars[i] == '1') continue;
// 查找可以交换的 '1',并根据剩余操作数确定交换位置
int j = i;
while (j > 0 && chars[j - 1] == '1' && k > 0) {
// 交换 '0' 和前面的 '1'
chars[j] = '1';
chars[j - 1] = '0';
j--;
k--; // 减少一次操作
}
}
return new String(chars);
}
public static void main(String[] args) {
System.out.println(solution(5, 2, "01010").equals("00101"));
System.out.println(solution(7, 3, "1101001").equals("0110101"));
System.out.println(solution(4, 1, "1001").equals("0101"));
}
}
代码解释
solution 函数首先将字符串转为字符数组,以便对字符进行交换操作。接着,从左到右遍历字符数组,当遇到 0 时,尽量将它与前面的 1 交换,直到 k 次操作耗尽或无法进一步优化。最后将字符数组转为字符串并返回。
知识总结
在学习和解决此题的过程中,我总结了以下几点关键知识:
- 贪心算法:贪心算法在解决最优序列问题时非常有效,尤其适用于局部最优逐步转化为全局最优的情况。
- 字符串操作技巧:字符串转换为字符数组后,可以更高效地操作每个字符。此方法尤其适合需要多次交换的情况。
- 交换次数的有效计算:对于每次交换,精确地减少
k值,确保在操作次数耗尽前实现最优排序。
通过这道题目,我不仅加深了对贪心算法的理解,还学习了如何通过局部最优策略逐步构建出字典序最小的字符串。