问题描述
小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'
题目解析
小U需要通过最多k次相邻字符的交换,将一个由 0 和 1 组成的字符串调整为字典序最小的字符串。字典序最小的字符串,可以理解为尽可能让 0 往前移。
题意要点
-
每次操作只能交换相邻的两个字符。
-
操作的次数不能超过
k次。 -
目标是返回调整后的字典序最小的字符串。
解题思路
为了实现字典序最小化,我们需要将尽可能多的 0 移到靠前的位置,同时保持最多执行 k 次操作的限制。基本思路如下:
-
遍历字符串: 从左到右扫描字符串,逐步确定当前字符是否需要用剩余的操作次数
k来交换更小的字符到当前 位置。 -
局部最优选择: 对于每个位置
i,在[i,i+k]范围内选择最小的字符,将其移动到i位置。-
如果最小字符的索引是
minIndex,移动该字符需要的操作次数是minIndex - i。 -
将该字符前的字符右移,同时减少操作次数
k。
-
-
终止条件: 如果
k次操作已经用完或者字符串扫描结束,直接返回结果。
核心代码详解
代码结构
-
遍历字符数组: 外层循环
for (int i=0;i<n && k>0; i++)控制从左到右扫描字符串,且在操作次数耗尽时终止。 -
找到最小字符: 在
[i,i+k]范围内找到最小的字符索引minIndex。 -
交换字符: 如果找到的最小字符不在当前位置,则需要移动它到当前
i。 -
更新状态:每次移动后,减少操作次数
k并更新字符串。
代码详细解析
public static String solution(int n, int k, String s) {
char[] arr = s.toCharArray(); // 将字符串转换为字符数组,方便操作
for (int i = 0; i < n && k > 0; i++) { // 遍历每个字符,直到操作次数耗尽
int maxIndex = Math.min(i + k, n - 1); // 当前最多可查看范围
int minIndex = i; // 初始化最小字符的索引
// 在范围 [i, maxIndex] 中寻找最小字符的索引
for (int j = i + 1; j <= maxIndex; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j; // 更新最小字符的位置
}
}
// 如果最小字符不在当前位置,进行字符移动
if (minIndex != i) {
int swapsNeeded = minIndex - i; // 需要的交换次数
for (int j = minIndex; j > i; j--) { // 将最小字符移到当前位置
arr[j] = arr[j - 1]; // 逐步右移
}
arr[i] = s.charAt(minIndex); // 将最小字符放到当前位置
k -= swapsNeeded; // 更新剩余的操作次数
}
}
return new String(arr); // 返回最终字符串
}
样例详解
样例1
- 输入:
n=5, k=2,S="01010" - 目标: 字典序最小
步骤:
-
初始字符串:
01010,k=2 -
i=0,范围
[0,2]:找到最小字符0(索引0),无需操作。 -
i=1,范围
[1,3]:找到最小字符0(索引2),需要1次操作。- 交换结果:
00110,k=1
- 交换结果:
-
i=2,范围
[2,4]:最小字符已在当前位置,无需操作。 -
最终字符串:
00101
输出:"00101"
样例2
- 输入:
n=7, k=3,S="1101001" - 目标: 字典序最小
步骤:
-
初始字符串:
1101001,k=3 -
i=0,范围
[0,3]:找到最小字符0(索引0),需要2次操作。- 交换结果:
1011001,k=1
- 交换结果:
-
i=1,范围
[1,2]:找到最小字符0(索引2),需要1次操作。- 交换结果:
0111001,k=0
- 交换结果:
-
i=2,操作次数用尽,停止。
-
最终字符串:
0110101
输出:"0110101"
样例3
- 输入:
n=4, k=1,S="1001" - 目标: 字典序最小
步骤:
-
初始字符串:
1001,k=1 -
i=0,范围
[0,1]:找到最小字符0(索引0),需要1次操作。- 交换结果:
0101,k=0
- 交换结果:
-
i=1,操作次数用尽,停止。
-
最终字符串:
0101
输出:"0101"
总结
这道题的关键在于:
-
范围限制: 每次只能在
k次交换范围内选择最优解。 -
局部最优: 在每个范围
[i,i+k]中选择最小字符并移动。 -
复杂度: 假设字符串长度为
n,每次查找最小值的复杂度为O(k),总时间复杂度为O(nk)。