字典序最小的01字符串 | 豆包MarsCode AI 刷题

39 阅读2分钟

问题描述

小U拥有一个由0和1组成的字符串,她可以进行最多k次操作,每次操作可以交换相邻的两个字符。目标是通过这些操作,使得最终得到的字符串字典序最小。

例如,小U当前有一个字符串 01010,她最多可以进行 2 次相邻字符交换操作。通过这些操作,她可以将字符串调整为 00101,这是可以通过不超过2次操作得到的字典序最小的字符串。

现在,小U想知道,经过最多k次操作后,能够得到的字典序最小的字符串是什么。

思路

  • 该问题可以通过使用两个指针来进行同步滑动来判定对应的情况
  • 一共有四种情况包括
    • 01:该情况不需要交换位置
    • 00:该情况也不需要交换位置
    • 10:该情况需要交换位置
    • 11:该情况也不需要交换位置,但需要判定下一个0在哪
  • 所以考虑left指针指向第一个1,让right直到碰到连续1后的第一个0即:11110情况,从右向左依次交换
  • 右向左遍历时需要一个临时指针来对right进行处理

代码实现

#include <iostream>
#include <vector>
#include <string>

using namespace std;

string solution(int n, int k, string s)
{
    // write code here
    int left = 0, right = 1, time = 0; // 初始化两个指针,time表示交换次数
    while (right <= n && time < k) // 判定条件次数不超过且右指针不出界
    {
        if (s[left] == '1') // 进入内部遍历
        {
            while (s[right] != '0' && right <= n)
                ++right; // 找到第一个不是0的索引
            int tmp = right - 1;
            while (time < k && tmp >= left && tmp < n - 1)
            {
                swap(s[tmp], s[right]); // 遍历进行交换
                tmp--;
                right--;
                time++;
            }
        }
        else
        {
            left++; // 为0则同时右移
            right++;
        }
    }
    // cout << s << endl;
    return s;
}


int main() {
    cout << (solution(5, 2, "01010") == "00101") << endl;
    cout << (solution(7, 3, "1101001") == "0110101") << endl;
    cout << (solution(4, 1, "1001") == "0101") << endl;
    return 0;
}
  1. 最需要关注的是测试时第四个样例:cout << (solution(5, 12, "00101") == "00011") << endl;
  2. 一开始编写的代码过不了该样例,经过debug后发现进入死循环,发现right指针一直未越过原始字符串所以通过将第二层遍历while将right超过n来最终跳出循环返回

算法分析

  • 外层循环最多遍历整个字符串执行n次,即O(n)
  • 内层循环找right,最坏情况,若没有0则会从当前值移动到末尾,执行O(n)次
  • 内层循环交换,受交换次数限制最多为k次,即O(k)

总复杂度

时间复杂度:最坏情况下复杂度为O(n+k) 空间复杂度:O(1)