问题描述
小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
- 输入:
思路解析
- 字符计数:统计字符串中每个字符(A、S、D、F)的出现次数。
- 目标频率计算:由于字符串长度是 4 的倍数,目标频率为
n / 4,其中n是字符串的长度。 - 频率差计算:计算每个字符与目标频率的差值。某个字符的出现次数过多,说明需要将其替换成其他字符;某个字符的出现次数过少,说明需要将其他字符减少来平衡。
- 替换最小子串的长度计算:为达到字符的平均分布,找到一个最小的子串长度,使得替换后所有字符的频率差达到平衡。
代码实现
接下来,我们将逐步实现这个算法。
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}
代码详解
- 字符计数:使用
HashMap统计每个字符的出现次数。 - 目标频率:计算每个字符的目标频率
n/4,并判断字符的频次是否超过目标频率,若超过则记录超出数量。 - 滑动窗口:采用滑动窗口技术动态调整窗口的大小,检查窗口中字符的频率是否已满足平衡条件。
- 平衡检查:通过辅助函数
isBalanced检查所有字符是否达到目标频率。
总结
通过以上步骤和代码实现,我们可以有效地找到需要最小替换子串的长度。这个过程不仅展示了字符串处理的技巧,也运用了滑动窗口和频率计数的有效方法,使得实现不仅符合题解,同时在性能上也比较高效。