问题序号:19
题目难度:困难
问题描述:小U拥有一个由0和1组成的字符串,她可以进行最多k次操作,每次操作可以交换相邻的两个字符。目标是通过这些操作,使得最终得到的字符串字典序最小。
例如,小U当前有一个字符串 01010,她最多可以进行 2 次相邻字符交换操作。通过这些操作,她可以将字符串调整为 00101,这是可以通过不超过2次操作得到的字典序最小的字符串。
现在,小U想知道,经过最多k次操作后,能够得到的字典序最小的字符串是什么。
测试用例如图:
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)
综上,字典序的题目往往需要我们有些巧思,能够通过题目的条件得出调整字典序的快捷方法。