题目传送门
题意简述
小U有一个由0和1组成的字符串,她可以进行最多 k 次操作,每次操作可以交换相邻的两个字符。目标是通过这些操作,使得最终得到的字符串字典序最小。字典序是指在字典中字符串的排列顺序,字典序越小的字符串越靠前。
解题思路
-
字符交换策略:为了使字符串的字典序最小,我们需要尽可能地将字符 '0' 移动到字符串的前面。每次操作允许交换相邻的字符,因此我们可以通过逐步交换 '0' 和其左侧的 '1' 来实现这一目标。
-
贪心算法:采用贪心策略,从左到右遍历字符串,遇到 '0' 时,尽可能地将其向左移动,直到达到边界或用完可用的交换次数 k。这样可以确保每次操作都尽可能地减少字典序。
-
操作次数限制:在每次交换操作后,减少可用的交换次数 k,并在 k 用完时停止进一步的交换操作。
代码实现
public class Main {
public static String solution(int n, int k, String s) {
char[] chars = s.toCharArray(); // 将字符串转换为字符数组
for (int i = 0; i < n; i++) {
int j = i;
// 尝试将当前字符向左移动,直到达到边界或没有足够的交换次数
while (i > 0 && chars[i - 1] == '1' && chars[i] == '0' && k > 0) {
// 交换相邻字符
swap(chars, i, i - 1);
k--; // 减少可用的交换次数
i--; // 移动到左边
}
i = j; // 恢复i的值
}
return new String(chars); // 将字符数组转换回字符串
}
// 交换字符数组中两个字符的位置
private static void swap(char[] chars, int i, int j) {
char temp = chars[i];
chars[i] = chars[j];
chars[j] = temp;
}
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"));
}
}
时间复杂度分析
该算法的时间复杂度为 𝑂(𝑛^2),其中𝑛是字符串的长度。最坏情况下,每个字符可能需要向左移动多次,导致嵌套循环的存在。然而,由于 k 的限制,实际操作次数通常远小于 𝑛^2。
用到的算法和数据结构
-
贪心算法:在每一步中,尽可能地将 '0' 向左移动,以减少字典序。
-
字符数组:用于存储和操作字符串中的字符,便于交换操作。
详细分析
在实现过程中,我们从左到右遍历字符串,遇到 '0' 时,检查其左侧是否有 '1',如果有且 k 大于0,则交换这两个字符,并减少 k。通过这种方式,我们可以在有限的操作次数内,尽可能地将 '0' 移动到字符串的前面,从而使得字符串的字典序最小。这种贪心策略确保了每次操作都尽可能地减少字典序,而不需要考虑全局的最优解,因为每次局部的最优选择(将 '0' 向左移动)最终会导致全局的最优解(字典序最小的字符串)。