问题描述
小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'
题目解读
- 只能交换相邻的字符,要尽量把0换到前面,贪心地优先换前面的数(保证字典序最小)
- 如果出现连续的1,要把末尾的0一步一步移到最前面
如果不考虑k的限制,最后的结果字符串一定是前面全是0,后面全是1(类似于000111),我们可以考虑遍历字符串,计算长度为i的字符串变成000111的交换次数,如果交换次数大于k, 计算结果字符串,i之后的字符串不会发生变化,假设连续的1长度为m, 要把之后的0移到前方(以获得最小字典序)需要移动m次,我们可以在遍历的时候维护出现1的次数cnt1, 在遇到0时即可计算出最小字典序的交换次数为cnt += cnt1
如果前i个字符串变为最小字典的交换次数大于k, 就说明无法让前i个字符串变为000111,就在前i-1的字符串最小字典序的情况进行计算,0往前移动k-cnt个,代码如下
string solution(int n, int k, string s) {
// write code here
//贪心的移动0
int cnt = 0; //交换次数
int cnt1 = 0; //1的个数
string res;
for(int i= 0; i<n; i++)
{
if(s[i]=='1')
{
cnt1++;
}
else { //如果遇到0,就计算移动到000111的交换次数
if(cnt+cnt1<=k)//0可以移动到1的首位
{
res.push_back('0');
cnt+=cnt1;
}
else {//0不能移动到1的首位
res.append(cnt1-(k-cnt),'1');
res.push_back('0');
res.append((k-cnt),'1');//只能移动k-cnt个1
res.insert(res.end(), s.begin()+i+1, s.end());//之后的字符串不变
return res;
}
}
}
res.append(cnt1, '1');//字符串可以移动成000111的形状,就把记录的1全部加入
return res;
}