问题描述
小U拥有一个由0和1组成的字符串,她可以进行最多k次操作,每次操作可以交换相邻的两个字符。目标是通过这些操作,使得最终得到的字符串字典序最小。
例如,小U当前有一个字符串 01010,她最多可以进行 2 次相邻字符交换操作。通过这些操作,她可以将字符串调整为 00101,这是可以通过不超过2次操作得到的字典序最小的字符串。
现在,小U想知道,经过最多k次操作后,能够得到的字典序最小的字符串是什么。
测试样例
样例1:
输入:
n = 5, k = 2, s = "01010"
输出:'00101'
样例2:
输入:
n = 7, k = 3, s = "1101001"
输出:'0110101'
样例3:
输入:
n = 4, k = 1, s = "1001"
输出:'0101'
解题思路
这道题的解题思路主要是贪心算法。我们需要尽可能地将字符串前面的字符变为’0’,因为在字典序中’0’比’1’小。以下是具体的步骤:
- 遍历字符串,对于每个字符,如果它是’1’,则尝试将其与前面的’0’交换,直到无法交换为止或者达到操作次数上限k。
- 每次交换操作,我们都要检查剩余的操作次数是否足够。如果不够,则停止交换。
- 在交换的过程中,我们需要记录每个’1’前面最近的’0’的位置,以便进行交换。
具体步骤如下:
- 初始化一个指针i从0开始遍历字符串。
- 对于每个位置i,如果s[i]是’1’,则从i开始向前查找最近的’0’,设其位置为j。
- 如果找到了这样的’0’,并且i - j <= k(即交换次数不超过k),则交换s[i]和s[j],并将k减去i - j。
- 继续向前查找,直到找不到可以交换的’0’或者k变为0。
- 如果k已经为0,则停止遍历,输出当前字符串。
- 如果遍历完整个字符串,输出最终得到的字符串。
代码展示
public class Main {
public static String solution(int n, int k, String s) {
char[] arr = s.toCharArray();
for (int i = 0; i < n; i++) {
if (arr[i] == '0') {
int j = i;
while (j > 0 && arr[j - 1] == '1' && k > 0) {
arr[j] = '1';
arr[j - 1] = '0';
j--;
k--;
}
if (k == 0) {
break;
}
}
}
return new String(arr);
}
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"));
}
}
代码解析
- 通过
toCharArray()方法将字符串转换为字符数组,因为字符串在Java中是不可变的,而字符数组可以方便地进行元素交换。 - 外层循环遍历字符数组,如果当前字符是’0’,则尝试将它与前面的’1’交换,直到没有更多的’1’可以交换,或者交换次数用完。
- 内层循环负责执行实际的交换操作,并且确保不会超出最大交换次数k。
- 如果k变为0,则退出外层循环,因为已经没有更多的交换次数了。
- 最后,将字符数组转换回字符串并返回。