解题思路
-
计算目标频次:
由于字符串长度总是 4 的倍数,要使得A
、S
、D
、F
四个字符出现的频次相等,那么目标频次就是字符串总长度除以4
。例如,对于长度为8
的字符串,每个字符理想的频次就是8 / 4 = 2
。 -
滑动窗口法遍历字符串:
- 从最小窗口长度(即
1
)开始,逐步增加窗口长度去遍历整个字符串,通过不断移动窗口来检查窗口内的字符是否满足四个字符频次相等的条件。 - 对于每个窗口长度,我们要遍历字符串的所有可能起始位置来获取不同的窗口子串进行分析。
- 从最小窗口长度(即
-
统计窗口内字符频次并检查条件:
- 在每个窗口子串中,需要统计
A
、S
、D
、F
这四个字符各自出现的频次。可以使用哈希表(HashMap
)来方便地进行频次统计,键为字符,值为该字符出现的次数。 - 统计完窗口内各字符频次后,将其与之前计算出的目标频次进行比较。如果四个字符的频次都与目标频次相等,说明找到了满足条件的窗口,记录该窗口长度,并继续寻找是否有更小长度的满足条件的窗口;若不相等,则继续扩大窗口或者移动窗口位置进行下一轮检查。
- 在每个窗口子串中,需要统计
过程代码
import java.util.HashMap;
import java.util.Map;
public class EqualCharFrequency {
// 统计给定字符串中指定字符的频次
private static Map<Character, Integer> countCharFrequency(String str) {
Map<Character, Integer> charCount = new HashMap<>();
charCount.put('A', 0);
charCount.put('S', 0);
charCount.put('D', 0);
charCount.put('F', 0);
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
charCount.put(c, charCount.get(c) + 1);
}
return charCount;
}
// 检查给定窗口内的字符频次是否都等于目标频次
private static boolean checkEqualFrequency(Map<Character, Integer> windowCharCount, int targetCount) {
for (char ch : new char[]{'A', 'S', 'D', 'F'}) {
if (windowCharCount.get(ch)!= targetCount) {
return false;
}
}
return true;
}
public static int minSubstringLength(String input) {
int length = input.length();
// 计算目标频次
int targetCount = length / 4;
// 统计整个输入字符串的字符频次(此处暂时不用,但可用于参考或后续可能的扩展)
Map<Character, Integer> totalCharCount = countCharFrequency(input);
int minLength = Integer.MAX_VALUE;
// 遍历不同的窗口大小
for (int windowSize = 1; windowSize <= length; windowSize++) {
// 遍历窗口的起始位置
for (int start = 0; start <= length - windowSize; start++) {
String window = input.substring(start, start + windowSize);
Map<Character, Integer> windowCharCount = countCharFrequency(window);
if (checkEqualFrequency(windowCharCount, targetCount)) {
minLength = Math.min(minLength, windowSize);
}
}
}
return minLength == Integer.MAX_VALUE? 0 : minLength;
}
}
完整测试代码(包含 main
方法用于测试样例)
public class Main {
public static void main(String[] args) {
// 测试样例1
String input1 = "ADDF";
System.out.println(EqualCharFrequency.minSubstringLength(input1));
// 测试样例2
String input2 = "ASAFASAFADDD";
System.out.println(EqualCharFrequency.minSubstringLength(input2));
// 测试样例3
String input3 = "SSDDFFFFAAAS";
System.out.println(EqualCharFrequency.minSubstringLength(input3));
// 测试样例4
String input4 = "AAAASSSSDDDDFFFF";
System.out.println(EqualCharFrequency.minSubstringLength(input4));
// 测试样例5
String input5 = "AAAADDDDAAAASSSS";
System.out.println(EqualCharFrequency.minSubstringLength(input5));
}
}
个人总结
- 关于解题思路:本题的核心在于通过滑动窗口的思想去寻找满足条件的最小子串长度。首先明确目标频次是解题的关键第一步,它为后续判断子串是否符合要求提供了标准。滑动窗口的方式能够系统地遍历字符串的所有可能子串情况,虽然时间复杂度相对较高,但对于这种小规模数据或者特定条件下的字符串处理是一种比较直观有效的方法。
- 关于代码实现:在代码中,将不同功能拆分成多个方法可以提高代码的可读性和可维护性。例如,单独的
countCharFrequency
方法用于统计字符频次,checkEqualFrequency
方法用于检查频次是否相等,使得minSubstringLength
主方法的逻辑更加清晰,专注于实现滑动窗口遍历及结果判断更新的流程。同时,合理运用HashMap
来处理字符频次的统计,利用了其键值对的特性,方便快捷地进行频次的记录与查询。在处理类似字符串相关的算法问题时,这种数据结构和模块化编程的思想有助于更好地组织代码逻辑,降低错误出现的概率,也方便后续根据需求对代码进行扩展或优化。总的来说,解决这类问题需要对字符串处理、数据结构(如哈希表)以及算法思想(如滑动窗口)有较好的理解和运用能力,通过不断练习此类题目可以提升编程技巧和逻辑思维能力。