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

164 阅读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'

思路分析

因为本题所涉及到的字符仅有'0'和'1',那么当我们比较第i个字符与第i+1个字符时,仅可能出现如下四种情况:

0与0
1与0
0与1
1与1

仔细观察并分析后不难得出结论:这四种情况只有1与0出现时,交换二者位置才能使得整个字符串的字典序变小。

所以我们需要做的事就变成了找到0与1,然后交换他们的位置

那么紧接着就自然地出现了第二个问题:从哪里开始找0与1?

这就要考虑到字典序的比较方式,字典序是按照字符的ASCII码值进行比较的顺序。对于二进制字符串,0的ASCII码值小于1,因此在比较时,0应该尽可能地出现在字符串的前面,1应该尽可能地出现在字符串的后面。也就是说高位的1对于整个字符串的字典序影响更大,也是我们优先需要交换的。

综上,我们需要从高位开始寻找"10"子串,并交换1与0的位置,直到k的次数用尽或已经不需要再交换位置。这种方法的时间复杂度是O(n*k),其中n是字符串的长度,k是允许的交换次数。

代码展示


public class Main {
  public static String solution(int n, int k, String s) {
      String str = s;
      boolean changed = true;//判断是否已经是字典序最小的序列
      while (k>0 && changed) {
          changed = false;
          StringBuilder newString = new StringBuilder();
          for (int i=0;i<n-1;i++) {
              if (str.charAt(i) == '1' && str.charAt(i+1) == '0') {
                  newString.append(str.substring(0,i));
                  newString.append("01");
                  newString.append(str.substring(i+2));
                  changed = true;
                  k--;
                  break;
              }
          }
          if (newString.length()==n) {
              str = newString.toString();
          }
      }
      return 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"));
  }
}