字典序最小的01字符串题目解析
引言
在字符串算法中,调整字符串以满足某种最优化条件是一个常见的问题。本次我们讨论的是如何在限定次数的相邻字符交换操作下,将由0和1组成的二进制字符串调整为字典序最小的形式。这不仅考验对字符串的理解,也需要巧妙地设计算法来最小化交换次数。
问题描述
给定一个仅包含字符0和1的长度为n的字符串s,你可以进行最多k次相邻字符交换操作。每次操作可以交换字符串中相邻的两个字符。你的目标是通过这些操作,使得最终得到的字符串的字典序最小。
示例:
- 输入:
s = "01010",k = 2 - 输出:
"00101"
通过最多2次交换操作,可以将字符串调整为00101,这是在限定操作次数内字典序最小的字符串。
解题思路
要使得字符串的字典序最小,我们需要尽可能地将字符0移动到前面。然而,每次只能交换相邻的字符,并且交换次数受到限制。因此,我们需要在有限的交换次数内,将尽可能多的0移动到前面。
具体思路如下:
- 遍历字符串:从左到右遍历字符串中的每个字符。
- 遇到字符
0时:尝试将其向前移动,直到无法移动或者达到交换次数限制。 - 更新交换次数:每次交换后,减少可用的交换次数
k。 - 终止条件:当交换次数用完
(k == 0),或者遍历完字符串时,停止操作。
图解示例
以字符串"01010"和k = 2为例:
初始状态:
| 索引 | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| 字符 | 0 | 1 | 0 | 1 | 0 |
-
第一个字符
0:- 已经在最前面,无需移动。
-
第二个字符
1:- 跳过,因为我们只在遇到
0时尝试移动。
- 跳过,因为我们只在遇到
-
第三个字符
0:-
尝试向前移动:
-
与前面的
1交换,k减1。 -
新状态:
索引 0 1 2 3 4 字符 0 0 1 1 0 -
再次与前面的
0(索引1)尝试交换,但前面是0,无需交换。
-
-
-
第四个字符
1:- 跳过。
-
第五个字符
0:-
尝试向前移动:
-
与前面的
1交换,k减1。 -
新状态:
索引 0 1 2 3 4 字符 0 0 1 0 1 -
由于
k已减为0,无法继续交换。
-
-
最终结果为"00101"。
代码详解
下面是实现上述思路的Java代码:
public class Main {
public static String solution(int n, int k, String s) {
char[] arr = s.toCharArray();
for (int i = 0; i < n && k > 0; i++) {
if (arr[i] == '0') {
int j = i;
// 尝试将当前的'0'向前移动
while (j > 0 && arr[j - 1] == '1' && k > 0) {
// 交换当前字符与前一个字符
arr[j] = '1';
arr[j - 1] = '0';
j--;
k--;
}
}
}
return new String(arr);
}
public static void main(String[] args) {
System.out.println(solution(5, 2, "01010")); // 输出: 00101
System.out.println(solution(7, 3, "1101001")); // 输出: 0110101
System.out.println(solution(4, 1, "1001")); // 输出: 0101
}
}
代码解释
方法 solution
-
参数说明:
int n:字符串的长度。int k:最多可以进行的交换次数。String s:初始的二进制字符串。
-
主要步骤:
-
将字符串转换为字符数组:便于修改字符。
char[] arr = s.toCharArray(); -
遍历字符数组:
for (int i = 0; i < n && k > 0; i++) {- 遍历条件为
i < n且k > 0,如果交换次数耗尽,直接退出循环。
- 遍历条件为
-
遇到字符
0时的处理:if (arr[i] == '0') {- 当当前字符为
0时,尝试向前移动。
- 当当前字符为
-
内层循环:将
0向前移动:int j = i; while (j > 0 && arr[j - 1] == '1' && k > 0) { arr[j] = '1'; arr[j - 1] = '0'; j--; k--; }-
条件:
j > 0:防止越界,确保有前一个字符。arr[j - 1] == '1':只有前一个字符是1,才需要交换。k > 0:确保还有剩余的交换次数。
-
操作:
- 交换当前位置的
0与前一个位置的1。 - 指针
j前移一位,继续尝试向前移动。 - 交换次数
k减1。
- 交换当前位置的
-
-
返回结果:
return new String(arr);- 将字符数组转换回字符串,作为最终结果。
-
结论
通过上述算法,我们在限定的交换次数内,将字符串调整为字典序最小的形式。该算法的时间复杂度为O(n^2),最坏情况下需要对每个0尝试向前移动,但由于交换次数有限,实际运行效率较高。
这种贪心的策略充分利用了每一次交换,使得0尽可能地向前移动,达到了全局最优解。
作者:AWM