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

57 阅读3分钟

问题描述

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

输入输出示例

  • 样例1

    • 输入:input = "ADDF"
    • 输出:1
  • 样例2

    • 输入:input = "ASAFASAFADDD"
    • 输出:3
  • 样例3

    • 输入:input = "SSDDFFFFAAAS"
    • 输出:1
  • 样例4

    • 输入:input = "AAAASSSSDDDDFFFF"
    • 输出:0
  • 样例5

    • 输入:input = "AAAADDDDAAAASSSS"
    • 输出:4

思路解析

  1. 字符计数:统计字符串中每个字符(A、S、D、F)的出现次数。
  2. 目标频率计算:由于字符串长度是 4 的倍数,目标频率为 n / 4,其中 n 是字符串的长度。
  3. 频率差计算:计算每个字符与目标频率的差值。某个字符的出现次数过多,说明需要将其替换成其他字符;某个字符的出现次数过少,说明需要将其他字符减少来平衡。
  4. 替换最小子串的长度计算:为达到字符的平均分布,找到一个最小的子串长度,使得替换后所有字符的频率差达到平衡。

代码实现

接下来,我们将逐步实现这个算法。

Java代码

Java
1import java.util.HashMap;
2
3public class Main {
4    public static int solution(String input) {
5        int n = input.length();
6        int target = n / 4; // 每个字符的目标频率
7        HashMap<Character, Integer> countMap = new HashMap<>();
8
9        // 统计字符出现频次
10        for (char c : input.toCharArray()) {
11            countMap.put(c, countMap.getOrDefault(c, 0) + 1);
12        }
13
14        // 计算每个字符的频率差
15        int excess = 0; // 超过目标数量的字符个数
16        for (char c : "ASDF".toCharArray()) {
17            int count = countMap.getOrDefault(c, 0);
18            if (count > target) {
19                excess += count - target; // 计算需要替换的总数
20            }
21        }
22
23        // 如果没有字符过多,无需替换
24        if (excess == 0) return 0;
25
26        // 使用滑动窗口找出最小替换子串
27        int left = 0, minLength = Integer.MAX_VALUE;
28        for (int right = 0; right < n; right++) {
29            // 逐渐扩大右边界,直至满足条件
30            countMap.put(input.charAt(right), countMap.get(input.charAt(right)) - 1);
31
32            // 检查是否所有超出目标数量的字符都已平衡
33            while (isBalanced(countMap, target)) {
34                // 更新最小子串长度
35                minLength = Math.min(minLength, right - left + 1);
36                // 移动左边界以寻找更小的有效子串
37                countMap.put(input.charAt(left), countMap.get(input.charAt(left)) + 1);
38                left++;
39            }
40        }
41
42        return minLength; // 返回找到的最小子串长度
43    }
44
45    // 检查当前字符频率是否平衡
46    private static boolean isBalanced(HashMap<Character, Integer> countMap, int target) {
47        for (char c : "ASDF".toCharArray()) {
48            if (countMap.getOrDefault(c, 0) > target) {
49                return false; // 如果有字符超出目标频率,返回不平衡
50            }
51        }
52        return true; // 所有字符均在目标范围内
53    }
54
55    public static void main(String[] args) {
56        System.out.println(solution("ADDF") == 1);
57        System.out.println(solution("ASAFASAFADDD") == 3);
58        System.out.println(solution("SSDDFFFFAAAS") == 1);
59        System.out.println(solution("AAAASSSSDDDDFFFF") == 0);
60        System.out.println(solution("AAAADDDDAAAASSSS") == 4);
61    }
62}

代码详解

  1. 字符计数:使用 HashMap 统计每个字符的出现次数。
  2. 目标频率:计算每个字符的目标频率 n/4,并判断字符的频次是否超过目标频率,若超过则记录超出数量。
  3. 滑动窗口:采用滑动窗口技术动态调整窗口的大小,检查窗口中字符的频率是否已满足平衡条件。
  4. 平衡检查:通过辅助函数 isBalanced 检查所有字符是否达到目标频率。

总结

通过以上步骤和代码实现,我们可以有效地找到需要最小替换子串的长度。这个过程不仅展示了字符串处理的技巧,也运用了滑动窗口和频率计数的有效方法,使得实现不仅符合题解,同时在性能上也比较高效。