字典序最小的01字符串问题解析
1. 问题描述
小U拥有一个由0和1组成的字符串,她可以进行最多k次操作,每次操作可以交换相邻的两个字符。目标是通过这些操作,使得最终得到的字符串字典序最小。
例如,小U当前有一个字符串 01010,她最多可以进行 2 次相邻字符交换操作。通过这些操作,她可以将字符串调整为 00101,这是可以通过不超过2次操作得到的字典序最小的字符串。
现在,小U想知道,经过最多k次操作后,能够得到的字典序最小的字符串是什么。
2. 解题思路
2.1 问题分析
在这个问题中,我们需要通过最多 k 次相邻字符交换操作,将由0和1组成的字符串调整为字典序最小的形式。字典序最小的字符串意味着我们希望尽可能早地将“0”放到字符串的前面。
2.2 目标
希望将字符串排序为字典序最小,这就要求先将“0”尽量移动到字符串的前面。
2.3 贪心策略
每遇到一个"0",我们尽可能地将其向左移动到最前面,直到达到可用的交换次数 k。如果在当前的位置能够进行交换,我们就一直向左移动,直到遇到一个不可交换的字符或没有剩余的 k 次操作。
2.4 边界条件
需要考虑的边界情况包括字符串中"0"的数量和位置,以确保我们不会超出可用的操作次数 k。
3. 示例
考虑字符串 01010 和 k=2:
- 初始状态:
0|1|0|1|0 - 第一次操作:
0|1|0|1|0→|0|0|1|1|0(此时需要2次交换) - 第二次操作:
0|0|1|1|0→|0|0||0|1|1(完成后得到的最小字典序为00101)
4. 代码
#include <iostream>
#include <vector>
#include <string>
using namespace std;
string solution(int n, int k, string s) {
for(int i=0; i<n && k>0; i++) {
if(s[i] == '0') { // 当当前字符是0时
int j = i;
while(j > 0 && s[j-1] == '1' && k > 0) { // 向左寻找1,进行交换
swap(s[j], s[j-1]); // 交换当前0和前面的1
j--; // 移动到左边
k--; // 减少可用的操作次数
}
}
}
return s; // 返回最终结果
}
int main() {
cout << (solution(5, 2, "01010") == "00101") << endl; // 输出1, 说明测试通过
cout << (solution(7, 3, "1101001") == "0110101") << endl; // 输出1
cout << (solution(4, 1, "1001") == "0101") << endl; // 输出1
return 0;
}
5. 代码详解
使用 for 循环遍历字符串的每个字符。当字符为 0 时:
- 初始化
j为当前索引,用于向左移动。 - 使用
while循环执行交换:条件是j > 0(防止数组越界)、前一个字符为1和k > 0(还有可用操作)。每次满足条件时,进行交换并更新j和k。