这道题目是一个典型的字符串排序问题,通过进行有限次相邻字符交换操作来使得字符串的字典序最小。问题的核心思想是:每次操作都应尽量将较小的字符(0)交换到前面的位置,以使得字典序变小。
问题分析
给定一个由字符 0 和 1 组成的字符串,要求在最多 k 次相邻交换操作后,使字符串的字典序最小。字典序是字符串排序的一种方式,简而言之,它是字符串按照字母顺序排列的顺序,因此我们要将 0 移到尽可能靠前的位置,1 移到尽量后的位置。
在实现过程中,交换次数是有限的,因此我们不能无限制地交换,而是需要在每一步优化交换操作的选择,以便用最少的交换次数实现最大的字典序优化。
思路解析
-
交换策略:
- 每次操作,尽量把
1后面最靠近的0向前移动。 - 通过扫描字符串,从前往后依次处理每个字符,当遇到
1时,在它后面寻找0,并将其向前交换,直到交换次数k用尽。
- 每次操作,尽量把
-
局部最优选择:
- 对于每个
1,我们可以在其后k个位置内找到一个0,并把它交换到1的位置。通过这种方式,我们希望通过交换得到最小字典序的字符串。
- 对于每个
-
交换限制:
- 在每次交换时,我们要确保交换次数不超过给定的
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 && k > 0; i++) {
// 如果当前字符是'1',我们需要找到最小的'0'来交换
if (chars[i] == '1') {
int minZeroIndex = -1;
// 在当前位置之后的k个字符内寻找'0'
for (int j = i + 1; j < n && j <= i + k; j++) {
if (chars[j] == '0') {
minZeroIndex = j;
break;
}
}
// 如果找到了'0',进行交换
if (minZeroIndex != -1) {
// 计算需要交换的次数
int swapsNeeded = minZeroIndex - i;
if (swapsNeeded <= k) {
// 进行交换
char temp = chars[minZeroIndex];
for (int j = minZeroIndex; j > i; j--) {
chars[j] = chars[j - 1];
}
chars[i] = temp;
// 更新剩余的交换次数
k -= swapsNeeded;
}
}
}
}
// 将字符数组转换回字符串并返回
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"));
}
}
代码详解
-
字符数组转换:我们首先将字符串
s转换成字符数组chars,因为字符串是不可变的,而字符数组是可变的,便于我们做交换操作。 -
外层循环:外层
for循环遍历字符数组,每次处理一个字符。如果该字符是1,我们就尝试在其后最多k个位置内寻找0,并进行交换。 -
寻找最小的 '0':对于每个
1,我们在其后最多k个字符内搜索第一个出现的0,如果找到,则将其与当前的1交换。 -
交换操作:一旦找到合适的
0,我们就进行交换。交换的过程是将该0挪动到1的位置,其他字符依次后移。这一步需要逐个交换,直到把0移到合适位置。 -
更新交换次数:每次交换之后,减少剩余的交换次数
k,直到没有足够的交换次数或已经处理完所有字符。 -
返回结果:最终,字符数组
chars被修改为最小字典序的字符串,我们将其转换回字符串并返回。
复杂度分析
-
时间复杂度:每次操作需要在最多
k个字符内进行一次查找,内层循环的最坏情况复杂度是O(k),外层循环遍历n个字符。所以总的时间复杂度为O(n * k)。 -
空间复杂度:我们只使用了一个字符数组来存储字符串,因此空间复杂度是
O(n)。
样例分析
-
样例1:
- 输入:
n = 5, k = 2, s = "01010" - 输出:
'00101' - 解释:最多进行 2 次交换,可以将
01010转换为00101。
- 输入:
-
样例2:
- 输入:
n = 7, k = 3, s = "1101001" - 输出:
'0110101' - 解释:最多进行 3 次交换,可以将
1101001转换为0110101。
- 输入:
-
样例3:
- 输入:
n = 4, k = 1, s = "1001" - 输出:
'0101' - 解释:最多进行 1 次交换,可以将
1001转换为0101。
- 输入:
总结
这道题目通过合理利用交换操作,尽量把 0 放到前面的位置,减少交换次数,从而实现字典序最小的字符串。通过逐步优化字符交换的策略,使得解法既简洁又高效。