AI刷题笔记

36 阅读3分钟

字典序最小的01字符串

题目解析

本题的目标是通过最多 k 次相邻字符交换操作,使一个由 0 和 1 组成的字符串的字典序最小。字典序最小意味着 0 要尽可能地排在前面。

思路分析

  1. 核心问题是找到并尽可能将字符串中的 0 向前交换,以达到字典序最小的效果。操作限制是每次只能交换相邻的两个字符,且最多可以进行 k 次操作。
  2. 关键点:字符串中 0 的位置需要尽量向前移动,而不违背交换次数的限制。最简单的方法是,找到第一个 1 后面最近的 0,然后交换它们,直到无法继续交换或达到最大操作次数。

代码详解

  1. 初始化

    • 将输入的字符串转化为字符数组 arr,方便在原数组上进行操作。
    • 使用数组 pos0 存储所有字符 '0' 的位置。
    • 使用 cnt 统计字符串中 0 的个数,方便后续定位。
  2. 找到第一个 '1'

    • 使用 last 标记字符串中第一个 '1' 的位置。
  3. 交换操作

    • last 小于当前位置的 '0' 时,尝试交换,直到交换次数 k 用完。
    • 如果当前要交换的 '0' 可以通过交换与 '1' 交换达到字典序更小的效果,就交换它们。
  4. 处理剩余的 0 和 1

    • 更新交换后的字符串,并继续寻找可以进行交换的 '0',直到无法继续交换为止。
  5. 最终返回结果

    • 完成交换后,返回更新后的字符串作为答案。

代码实现

public class Main {
    public static String solution(int n, int k, String s) {
        char[] arr = s.toCharArray(); 
        int[] pos0 = new int[n + 1]; 
        int cnt = 0;

        int last = 0; 
        for (int i = 0; i < n; i++) {
            if (arr[i] == '0') {
                pos0[++cnt] = i + 1; 
            } else if (last == 0) {
                last = i + 1; 
            }
        }
        
        if (last == 0 || last >= pos0[cnt]) {
            return s;
        }

        int i = 1; 
        while (i <= cnt && last > pos0[i]) {
            i++; 
        }

        while (k > 0 && i <= cnt && last <= n) {
            int R0 = pos0[i]; 
            int L1 = last;

            if (R0 - L1 <= k) { 
                k -= (R0 - L1);
                arr[R0 - 1] = '1'; 
                arr[L1 - 1] = '0';
                last++;
                i++;
            } else { 
                arr[R0 - 1] = '1';
                arr[R0 - 1 - k] = '0';
                k = 0;
            }

            while (last <= n && arr[last - 1] == '0') {
                last++;
            }
        }

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

知识总结

在使用豆包MarsCode AI刷题过程中,我总结出了一些有用的知识点:

  1. 字符串操作:对于这类字符串交换的问题,可以通过将字符串转换为字符数组进行操作,这样更方便操作和修改字符。
  2. 贪心算法:在本题中,我们采用贪心算法的思想,尽可能将 '0' 向前移动,这样能最大程度地降低字典序。
  3. 边界条件:在处理字符串时,必须考虑到所有的边界情况,如没有 '1' 的情况、所有 '1' 都在 '0' 后面等,这些都需要在算法中进行合理判断和处理。
  4. 优化交换次数:利用 k 的限制,尽可能在最小交换次数内实现目标。通过对位置的合理判断,避免不必要的交换。

学习计划

通过在豆包MarsCode AI平台刷题,我总结出了一个高效学习算法的计划:

  1. 制定学习目标:每周设定一个学习目标,比如掌握常见的算法和数据结构,尤其是排序、动态规划和图论等。
  2. 错题本:对于每次刷题时出现的错误,可以记录下来并总结原因,定期复习这些错题,确保理解每一个错误的背后逻辑。
  3. 重点难点突破:每次遇到难题时,分析题目的思路和代码,理解其中的细节,特别是那些优化方法和空间复杂度控制。