问题描述
小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
为了实现这个功能,可以使用滑动窗口和计数的方法,核心思路如下:
- 频次要求:字符串长度为4的倍数,假设其长度为
n
,那么每个字符A
、S
、D
、F
的理想频次应为n / 4
。 - 滑动窗口:我们可以使用滑动窗口来检查一个子串,并尝试使得剩余字符的频次满足要求。我们在窗口中统计字符的出现频次,判断窗口外的字符是否满足平衡条件。
- 调整窗口:不断调整窗口的大小和位置,直到窗口内的字符数量可以满足平衡条件。这样可以获得最小的子串长度。
下面是完整的代码实现:
import java.util.HashMap;
import java.util.Map;
public class Main {
public static int solution(String input) {
int n = input.length();
int targetCount = n / 4;
Map<Character, Integer> countMap = new HashMap<>();
// 初始化每个字符的频次
for (char c : input.toCharArray()) {
countMap.put(c, countMap.getOrDefault(c, 0) + 1);
}
// 检查当前是否已经平衡
if (isBalanced(countMap, targetCount)) return 0;
int minLength = n;
int left = 0;
// 滑动窗口遍历
for (int right = 0; right < n; right++) {
// 窗口右边字符计数减少
char rightChar = input.charAt(right);
countMap.put(rightChar, countMap.get(rightChar) - 1);
// 尝试平衡检查
while (isBalanced(countMap, targetCount) && left <= right) {
minLength = Math.min(minLength, right - left + 1);
// 窗口左边字符计数恢复
char leftChar = input.charAt(left);
countMap.put(leftChar, countMap.get(leftChar) + 1);
left++;
}
}
return minLength;
}
// 判断字符频次是否满足平衡
private static boolean isBalanced(Map<Character, Integer> countMap, int targetCount) {
return countMap.getOrDefault('A', 0) <= targetCount &&
countMap.getOrDefault('S', 0) <= targetCount &&
countMap.getOrDefault('D', 0) <= targetCount &&
countMap.getOrDefault('F', 0) <= targetCount;
}
public static void main(String[] args) {
System.out.println(solution("ADDF") == 1);
System.out.println(solution("ASAFASAFADDD") == 3);
System.out.println(solution("SSDDFFFFAAAS") == 1);
System.out.println(solution("AAAASSSSDDDDFFFF") == 0);
System.out.println(solution("AAAADDDDAAAASSSS") == 4);
}
}
代码说明:
- 计数初始化:首先统计输入字符串中每个字符的出现次数。
- 滑动窗口:使用左右指针(
left
和right
)来定义窗口,调整窗口大小以寻找符合条件的最小子串。 - 判断是否平衡:每次移动窗口时检查窗口外的字符是否满足平衡要求。如果满足,更新最小长度。
- 输出结果:最终返回最小的子串长度。