学习方法与心得1 | 豆包MarsCode AI刷题

97 阅读3分钟

字典序最小的01字符串问题解析

1. 问题描述

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

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

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

2. 解题思路

2.1 问题分析

在这个问题中,我们需要通过最多 k 次相邻字符交换操作,将由0和1组成的字符串调整为字典序最小的形式。字典序最小的字符串意味着我们希望尽可能早地将“0”放到字符串的前面。

2.2 目标

希望将字符串排序为字典序最小,这就要求先将“0”尽量移动到字符串的前面。

2.3 贪心策略

每遇到一个"0",我们尽可能地将其向左移动到最前面,直到达到可用的交换次数 k。如果在当前的位置能够进行交换,我们就一直向左移动,直到遇到一个不可交换的字符或没有剩余的 k 次操作。

2.4 边界条件

需要考虑的边界情况包括字符串中"0"的数量和位置,以确保我们不会超出可用的操作次数 k

3. 示例

考虑字符串 01010 和 k=2

  • 初始状态:0|1|0|1|0
  • 第一次操作:0|1|0|1|0 → |0|0|1|1|0(此时需要2次交换)
  • 第二次操作:0|0|1|1|0 → |0|0||0|1|1(完成后得到的最小字典序为00101

4. 代码

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

using namespace std;  

string solution(int n, int k, string s) {  
    for(int i=0; i<n && k>0; i++) {  
        if(s[i] == '0') { // 当当前字符是0时  
            int j = i;  
            while(j > 0 && s[j-1] == '1' && k > 0) { // 向左寻找1,进行交换  
                swap(s[j], s[j-1]); // 交换当前0和前面的1  
                j--; // 移动到左边  
                k--; // 减少可用的操作次数  
            }  
        }  
    }  
    return s; // 返回最终结果  
}  

int main() {  
    cout << (solution(5, 2, "01010") == "00101") << endl; // 输出1, 说明测试通过  
    cout << (solution(7, 3, "1101001") == "0110101") << endl; // 输出1  
    cout << (solution(4, 1, "1001") == "0101") << endl; // 输出1  
    return 0;  
}

5. 代码详解

使用 for 循环遍历字符串的每个字符。当字符为 0 时:

  • 初始化 j 为当前索引,用于向左移动。
  • 使用 while 循环执行交换:条件是 j > 0(防止数组越界)、前一个字符为 1 和 k > 0(还有可用操作)。每次满足条件时,进行交换并更新 j 和 k