问题描述
小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
问题分析:
我们要确保每个字符出现的频率都达到目标值 n / 4。如果当前已经平衡(即每个字符的频率都为 n / 4),则返回 0。否则,我们需要找到最小的子串长度,使得通过替换这个子串中的字符,可以使字符的频率达到目标。
1. 频率统计与目标设定:
- 问题的关键: 我们的目标是使字符串中每个字符
'A','S','D','F'的出现频率相等。根据题目要求,字符串的长度n是 4 的倍数,所以每个字符的目标频率为n / 4。 - 思路: 我们首先统计整个字符串中每个字符的出现频率,并检查当前的频率是否已经符合目标(
n / 4)。如果已经符合目标,就可以直接返回 0,因为不需要进行任何替换。
2. 滑动窗口与子串检查:
- 子串的检查: 如果频率不平衡,我们需要寻找一个最小的子串,通过替换该子串中的字符,使得所有字符的频率达到目标值。
- 滑动窗口: 我们需要遍历所有可能的子串。对于每个子串,计算其字符频率,并检查替换该子串后是否能让整体字符频率达到目标。为了高效地计算每个子串的字符频率,我们可以直接统计每个子串的频率,而不需要每次重新计算整个字符串的频率。
3. 频率更新与验证:
- 更新频率: 对于每个子串,先统计它的字符频率(用一个哈希表
sub_freq)。然后,将这些频率从整个字符串的频率freq中扣除(使用new_freq来表示更新后的频率)。 - 检查平衡: 检查更新后的频率是否满足目标要求:对于每个字符,检查它的频率是否超过了目标频率
n / 4。如果超过了,则当前子串无法达到平衡,继续检查下一个子串。
4. 早期终止:
- 优化: 如果某个子串可以通过替换达到平衡,那么立即返回该子串的长度,因为我们正在寻找最小的子串长度。这可以避免不必要的计算,提升效率。
5. 时间复杂度考虑:
- 对于长度为
n的字符串,最多需要检查所有长度从1到n的子串。对于每个子串,需要统计它的字符频率并验证平衡。因此,时间复杂度大约是O(n^2),每次检查的复杂度为O(n)。对于较小的输入规模,这个复杂度是可以接受的。
6. 边界情况处理:
- 输入已经平衡: 如果输入字符串已经符合目标频率,我们应该立即返回 0。
- 输入字符串不可平衡: 如果没有任何子串可以替换来平衡字符串(理论上不应该发生,但依然需要考虑),返回
-1。
代码实现:
#include <iostream>
#include <string>
#include <unordered_map>
int solution(const std::string& input_str) {
int n = input_str.size();
int target = n / 4; // 因为是4的倍数,所以每个字符应该出现 n / 4 次
// 统计每个字符出现的次数
std::unordered_map<char, int> freq;
for (char c : input_str) {
freq[c]++;
}
// 如果已经平衡,返回 0
if (freq['A'] == target && freq['S'] == target && freq['D'] == target && freq['F'] == target) {
return 0;
}
// 从小到大尝试子串长度
for (int length = 1; length <= n; ++length) {
// 遍历所有可能的起始位置
for (int start = 0; start <= n - length; ++start) {
// 统计子串的字符频率
std::unordered_map<char, int> sub_freq;
for (int i = start; i < start + length; ++i) {
sub_freq[input_str[i]]++;
}
// 检查当前子串替换后是否能达到平衡
bool valid = true;
std::unordered_map<char, int> new_freq = freq;
for (const auto& entry : sub_freq) {
new_freq[entry.first] -= entry.second;
}
// 判断是否能平衡
for (const auto& entry : new_freq) {
if (entry.second > target) {
valid = false;
break;
}
}
if (valid) {
return length;
}
}
}
return -1; // 如果没有找到合适的子串
}
int main() {
std::cout << (solution("ADDF") == 1) << std::endl;
std::cout << (solution("ASAFASAFADDD") == 3) << std::endl;
std::cout << (solution("AAAADDDDAAAASSSS") == 4) << std::endl;
return 0;
}