最小替换字串长度|豆包MarsCode AI刷题

123 阅读3分钟

题目要求:小F得到了一个特殊的字符串,这个字符串只包含字符ASDF,其长度总是4的倍数。他的任务是通过尽可能少的替换,使得ASDF这四个字符在字符串中出现的频次相等。求出实现这一条件的最小子串长度。

问题理解

一个只包含字符 ASDF 的字符串,且字符串的长度总是4的倍数。目标是使得这四个字符在字符串中出现的频次相等。为了实现这一目标,需要通过尽可能少的替换操作来达到这个条件。

数据结构选择

  1. 频次统计:首先,我们需要统计每个字符在字符串中出现的频次。
  2. 差值计算:然后,计算每个字符需要增加或减少的频次,以使得每个字符的频次达到目标频次(即字符串长度除以4)。
  3. 滑动窗口:使用滑动窗口技术来找到最小的子串,使得该子串中包含足够多的字符来满足差值要求。

算法步骤

  1. 初始化

    • 计算目标频次 targetFreq,即字符串长度除以4。
    • 统计每个字符的当前频次。
    • 计算每个字符需要增加或减少的频次 diff
  2. 滑动窗口

    • 使用两个指针 left 和 right 来表示窗口的左右边界。
    • 扩展窗口(移动 right),并更新窗口内每个字符的频次。
    • 当窗口内的字符频次满足 diff 要求时,记录当前窗口的长度,并尝试缩小窗口(移动 left)。
    • 继续上述过程,直到遍历完整个字符串。
  3. 返回结果

    • 返回找到的最小窗口长度。

算法实现

public class Main {
    public static int solution(String input) {
        int n = input.length();
        int targetFreq = n / 4; // 目标频次

        // 统计当前频次
        int[] freq = new int[4]; // 0: A, 1: S, 2: D, 3: F
        for (char c : input.toCharArray()) {
            freq[charToIndex(c)]++;
        }

        // 计算差值
        int[] diff = new int[4];
        for (int i = 0; i < 4; i++) {
            diff[i] = Math.max(0, freq[i] - targetFreq);
        }

        // 如果所有字符的频次已经相等,直接返回0
        if (diff[0] == 0 && diff[1] == 0 && diff[2] == 0 && diff[3] == 0) {
            return 0;
        }

        // 滑动窗口
        int left = 0, right = 0;
        int minLen = n; // 初始化为最大可能值
        int[] windowCount = new int[4];

        while (right < n) {
            // 扩展窗口
            windowCount[charToIndex(input.charAt(right))]++;
            right++;

            // 检查窗口是否满足条件
            while (isValidWindow(windowCount, diff)) {
                minLen = Math.min(minLen, right - left);
                // 缩小窗口
                windowCount[charToIndex(input.charAt(left))]--;
                left++;
            }
        }

        return minLen;
    }

    // 将字符转换为索引
    private static int charToIndex(char c) {
        switch (c) {
            case 'A': return 0;
            case 'S': return 1;
            case 'D': return 2;
            case 'F': return 3;
            default: throw new IllegalArgumentException("Invalid character: " + c);
        }
    }

    // 检查窗口是否满足条件
    private static boolean isValidWindow(int[] windowCount, int[] diff) {
        for (int i = 0; i < 4; i++) {
            if (windowCount[i] < diff[i]) {
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args) {
        // 你可以添加更多测试用例
        System.out.println(solution("ADDF") == 1);
        System.out.println(solution("ASAFASAFADDD") == 3);
    }
}

关键点

  • 频次统计:确保正确统计每个字符的频次。
  • 差值计算:正确计算每个字符需要增加或减少的频次。
  • 滑动窗口:确保窗口内的字符频次满足 diff 要求,并找到最小的窗口长度。