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

50 阅读3分钟

问题描述

小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’,因为在字典序中’0’比’1’小。以下是具体的步骤:

  1. 遍历字符串,对于每个字符,如果它是’1’,则尝试将其与前面的’0’交换,直到无法交换为止或者达到操作次数上限k。
  2. 每次交换操作,我们都要检查剩余的操作次数是否足够。如果不够,则停止交换。
  3. 在交换的过程中,我们需要记录每个’1’前面最近的’0’的位置,以便进行交换。

具体步骤如下:

  1. 初始化一个指针i从0开始遍历字符串。
  2. 对于每个位置i,如果s[i]是’1’,则从i开始向前查找最近的’0’,设其位置为j。
  3. 如果找到了这样的’0’,并且i - j <= k(即交换次数不超过k),则交换s[i]和s[j],并将k减去i - j。
  4. 继续向前查找,直到找不到可以交换的’0’或者k变为0。
  5. 如果k已经为0,则停止遍历,输出当前字符串。
  6. 如果遍历完整个字符串,输出最终得到的字符串。

代码展示

public class Main {
    public static String solution(int n, int k, String s) {
        char[] arr = s.toCharArray();

        for (int i = 0; i < n; i++) {
            if (arr[i] == '0') {
                int j = i;
                while (j > 0 && arr[j - 1] == '1' && k > 0) {
                    arr[j] = '1';
                    arr[j - 1] = '0';
                    j--;
                    k--; 
                }
                if (k == 0) {
                    break;
                }
            }
        }

        return new String(arr);
    }

    public static void main(String[] args) {
        System.out.println(solution(5, 2, "01010").equals("00101")); 
        System.out.println(solution(7, 3, "1101001").equals("0110101"));  
        System.out.println(solution(4, 1, "1001").equals("0101")); 
    }
}

代码解析

  • 通过toCharArray()方法将字符串转换为字符数组,因为字符串在Java中是不可变的,而字符数组可以方便地进行元素交换。
  • 外层循环遍历字符数组,如果当前字符是’0’,则尝试将它与前面的’1’交换,直到没有更多的’1’可以交换,或者交换次数用完。
  • 内层循环负责执行实际的交换操作,并且确保不会超出最大交换次数k。
  • 如果k变为0,则退出外层循环,因为已经没有更多的交换次数了。
  • 最后,将字符数组转换回字符串并返回。