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

56 阅读3分钟

字典序最小的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'

题解

  1. 这个题目有点需要我们贪心地进行选择,你需要通过最多 k 次相邻字符交换操作,使得给定的由 0 和 1 组成的字符串 s 的字典序最小。字典序最小意味着字符串中的 0 应该尽可能地排在前面,1 应该尽可能地排在后面。
  2. 那么我们就可以在有限的操作次数内,尽量把 0 换到前面,这样生成的字符串的字典序也会更小,那么我们可以遍历这个字符串,然后对于遇到是 1 的位置,可以先进行保存,然后在遇到 0 的时候就贪心地跟最前面的 1 交换,如果次数不够那么就跟次数允许范围内最前的 1 交换。

数据结构选择

  • 队列:可以使用队列来存储字符串中 1 的位置。这样可以在遇到 0 时,快速找到最近的 1 进行交换。

算法步骤

  1. 遍历字符串:从左到右遍历字符串 s

  2. 遇到 1 时:将 1 的位置加入队列。

  3. 遇到 0 时

    • 如果队列不为空,尝试将 0 与队列中的 1 进行交换。
    • 计算交换所需的步数(即 0 的位置与队列中 1 的位置之间的距离)。
    • 如果步数小于等于 k,则进行交换,并更新 k 的值。
    • 如果步数大于 k,则不进行交换。
  4. 更新队列:每次交换后,更新队列中的 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;
}