字典序最小的01字符串
题目类型
思维题,模拟题
问题描述
- 小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'
题解
- 这个题目有点需要我们贪心地进行选择,你需要通过最多
k次相邻字符交换操作,使得给定的由0和1组成的字符串s的字典序最小。字典序最小意味着字符串中的0应该尽可能地排在前面,1应该尽可能地排在后面。 - 那么我们就可以在有限的操作次数内,尽量把
0换到前面,这样生成的字符串的字典序也会更小,那么我们可以遍历这个字符串,然后对于遇到是1的位置,可以先进行保存,然后在遇到0的时候就贪心地跟最前面的1交换,如果次数不够那么就跟次数允许范围内最前的1交换。
数据结构选择
- 队列:可以使用队列来存储字符串中
1的位置。这样可以在遇到0时,快速找到最近的1进行交换。
算法步骤
-
遍历字符串:从左到右遍历字符串
s。 -
遇到
1时:将1的位置加入队列。 -
遇到
0时:- 如果队列不为空,尝试将
0与队列中的1进行交换。 - 计算交换所需的步数(即
0的位置与队列中1的位置之间的距离)。 - 如果步数小于等于
k,则进行交换,并更新k的值。 - 如果步数大于
k,则不进行交换。
- 如果队列不为空,尝试将
-
更新队列:每次交换后,更新队列中的
1的位置。
关键点
- 队列的使用:队列用于存储
1的位置,方便快速找到最近的1进行交换。 - 交换条件:只有在交换所需的步数小于等于
k时才进行交换。 - 更新队列:每次交换后,更新队列中的
1的位置。
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <algorithm>
std::string solution(int n, int k, std::string s) {
std::queue<int> q;
for(int i = 0; i < s.size(); i++) {
if(s[i] == '1') q.push(i);
else{
if(k <= 0) break;
if(q.size() == 0) continue;
int cnt = i - q.front();
if(cnt <= k) {
k -= cnt;
std::swap(s[q.front()], s[i]);
q.pop();
q.push(i);
}
else{
while(i - q.front() != k) q.pop();
std::swap(s[q.front()], s[i]);
break;
}
}
}
return s;
}