青训营X豆包MarsCode AI刷题第19题(困难) | 豆包MarsCode AI刷题

75 阅读3分钟

问题序号:19

题目难度:困难

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

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

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

测试用例如图:

image.png

1.题目理解

这道题首先要注意到操作只能是交换相邻的两个字符,同时限制的是在固定操作次数的情况下,使得当前字符串转化为字典序最小的字符串。同时需要注意字符串中只包含0和1字符,那么字典序最小就是尽可能让0在前面,1在后面。那么这道题是不是觉得就没那么难了?我们只需要尽可能的将1挪到后面即可,同时限制操作步数为k次

2.代码(JAVA)

    public static String solution(int n, int k, String s) {
        // write code here
        char[] str=s.toCharArray();

        for(int i=0;i<n;i++){
            int j = i;
            while(i!=0 && str[i-1] == '1' && str[i] == '0'){
                char a = str[i];
                str[i] = str[i-1];
                str[i-1] = a;
                k--;
                i--;
                if(k==0){
                    return new String(str);
                }
            }
            i=j;
        }
        return new String(str);
    }

    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"));
    }
}

3.代码讲解

我们首先从最左侧开始,如果检测到当然字符为0且左侧字符为1,那么说明这两个字符需要交换,我们将其交换后将下标-1,然后看看这个0,利用j保存当前下标,然后将这个0不断的向左侧移动,同时不要忘记给k--,如果k==0,说明已经达到题目限定的操作次数,直接结束即可。

一个循环结束后需要将i恢复到我们保存的j值,这样就可以确保不断的向右找,尽量将最左侧0和1交换移动到前面(此时操作次数最小),保证字典序。

这道题虽然是困难题,但是思路并不复杂

4.相似题目

下面我们来看一道相似的字典序题目,来自于leetcode的386题

题目描述: 给定一个整数 n, 返回从 1 到 n 的字典顺序。

例如,给定 n = 13,返回 [1,10,11,12,13,2,3,4,5,6,7,8,9] 。

请尽可能的优化算法的时间复杂度和空间复杂度。 输入的数据 n 小于等于 5,000,000。

这道题有两种做法:

(1)排序法:直接将所有整数的字符串形式加入到数组中,然后进行排序即可,时间复杂度为O(nlogn),空间复杂度为O(n)

(2)字典树递归法:假设有如下这棵树,我们能够发现只需要对这棵树进行前序遍历即可完成字典序的排序。时间复杂度可以优化到O(n)

72ECD3B42BD1F26D0E4FB53516A1025A.jpg

综上,字典序的题目往往需要我们有些巧思,能够通过题目的条件得出调整字典序的快捷方法。