AI刷题字典序最小的01字符串--贪心

96 阅读2分钟

问题描述

小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;
}