题目解析:字典序最小化字符串问题| 豆包MarsCode AI 刷题

60 阅读4分钟

问题描述

本题要求在限定的交换次数 k 内,通过相邻字符的交换操作,将一个由01组成的字符串调整为字典序最小的字符串。


样例解析

为了更好地理解问题,让我们逐个分析题目给出的样例:

样例1:

  • 输入:n = 5, k = 2, s = "01010"
  • 输出:"00101"
    • 分析:
      • 第1步,将0与第2个字符1交换,得到00110
      • 第2步,将1与第3个字符0交换,最终得到00101
      • 结果00101是满足条件下字典序最小的字符串。

样例2:

  • 输入:n = 7, k = 3, s = "1101001"
  • 输出:"0110101"
    • 分析:
      • 第1步,将第3个字符0移动到第1位,得到1011001(消耗2次交换)。
      • 第3步,将第2个字符1与其后面的0交换,得到0110101
      • 字典序最小的结果是0110101

样例3:

  • 输入:n = 4, k = 1, s = "1001"
  • 输出:"0101"
    • 分析:
      • 只能进行一次交换,将第1位的1与第2位的0交换,得到0101
      • 这是可能的字典序最小结果。

解题思路

本题的核心在于贪心算法的应用。为了得到字典序最小的字符串,需要尽可能将较小的字符(0)向前移动,同时尽量减少不必要的交换操作,优化 k 的利用。

具体思路如下:

  1. 寻找当前最小字符的位置:
  • 在剩余交换次数 k 允许的范围内,找到当前字符之后的最小字符,并记录其位置。
  1. 将最小字符移动到当前位置:
  • 从找到的最小字符的位置,逐步向当前位置移动,通过多次相邻交换完成位置调整,并更新剩余交换次数 k。
  1. 重复上述步骤:
  • 每次从未排序的部分开始,继续寻找并移动最小字符,直到 k = 0 或字符串排序完成。

这种贪心策略能够确保每次调整后,当前子串尽可能字典序最小化。


代码实现

public class Main {
    /**
     * 贪心算法实现字典序最小化
     *
     * @param n 字符串长度
     * @param k 最大交换次数
     * @param s 输入字符串
     * @return 字典序最小的字符串
     */
    public static String solution(int n, int k, String s) {
        char[] arr = s.toCharArray(); 
        for (int i = 0; i < n && k > 0; i++) {
            int pos = i;
            for (int j = i + 1; j < n && j - i <= k; j++) {
                if (arr[j] < arr[pos]) {
                    pos = j;
                }
            }
            for (int j = pos; j > i; j--) {
                char temp = arr[j];
                arr[j] = arr[j - 1];
                arr[j - 1] = temp;
                k--;
            }
        }
        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"));
    }
}

代码逻辑解析

  1. 外层循环:
  • 遍历字符串的每个字符,从左到右逐步处理。
  • 对于每个字符,尝试将当前位置调整为该范围内最小的字符。
  1. 内层循环:
  • 在 [i, i + k] 范围内,寻找字典序最小的字符位置。
  1. 交换操作:
  • 将找到的最小字符,通过相邻交换逐步移动到当前位置 i。
  • 每次交换后,更新剩余交换次数 k。

时间复杂度分析

  • 时间复杂度:

    • 外层循环运行 n 次。
    • 每次内层循环最多检查 k 个字符,复杂度为 O(k)O(k)
    • 最坏情况下,总体时间复杂度为 O(nk)O(n*k)
  • 空间复杂度:

    • 主要使用了一个字符数组 arr,因此空间复杂度为 O(n)O(n)

思路验证与总结

  1. 核心算法验证:
  • 通过贪心算法的每次局部最优选择,确保最终全局最优。
  • 每次优先处理较小字符的移动,避免多余操作。
  1. 优化方向:
  • 当前算法直接实现了贪心策略,代码简洁清晰。
  • 对于大规模字符串,若 kk 较小时,可以通过剪枝优化进一步减少无意义搜索。
  1. 实际应用场景:
  • 此类问题常用于字符串排序、编码优化等领域。
  • 贪心策略的设计能够快速找到近似最优解。

通过这道题,我们可以掌握贪心算法的应用,理解字符串字典序问题的本质逻辑。