问题描述
小F得到了一个特殊的字符串,这个字符串只包含字符A、S、D、F,其长度总是4的倍数。他的任务是通过尽可能少的替换,使得A、S、D、F这四个字符在字符串中出现的频次相等。求出实现这一条件的最小子串长度。
总体思路
本题的核心目标是在给定的特殊字符串(只含字符 A、S、D、F 且长度为 4 的倍数)中,通过最少的替换操作让 A、S、D、F 这四个字符出现的频次相等,为此采用滑动窗口的方法来寻找满足条件的最小子串长度。
std::vector<int> count(4, 0); // 0: 'A', 1: 'S', 2: 'D', 3: 'F'
for (char c : input) {
if (c == 'A') count[0]++;
else if (c == 'S') count[1]++;
else if (c == 'D') count[2]++;
else if (c == 'F') count[3]++;
}
- 创建一个大小为 4 的整数向量
count,用于分别统计字符A、S、D、F在输入字符串中出现的频次。初始时都设置为 0。 - 通过遍历输入字符串
input,根据当前字符是A、S、D还是F,相应地增加count向量中对应位置的计数。
std::vector<int> need(4, 0);
for (int i = 0; i < 4; ++i) {
need[i] = std::max(0, count[i] - target);
}
- 创建另一个大小为 4 的整数向量
need,用于表示每个字符需要替换的次数。 - 通过遍历
count向量,计算每个字符当前频次与目标频次的差值。如果差值大于 0,说明该字符出现次数过多,需要进行替换,将差值存入need向量对应位置;如果差值小于等于 0,则该位置设置为 0,表示不需要替换该字符。
if (need[0] == 0 && need[1] == 0 && need[2] == 0 && need[3] == 0) {
return 0;
}
- 在此处检查所有字符的
need值是否都为 0,即是否所有字符的频次已经相等。如果是,说明不需要进行任何替换操作,直接返回 0,表示最小子串长度为 0。
int left = 0, right = 0;
int minLen = n;
std::vector<int> window(4, 0);
while (right < n) {
// 扩展窗口
char c = input[right];
if (c == 'A') window[0]++;
else if (c == 'S') window[1]++;
else if (c == 'D') window[2]++;
else if (c == 'F') window[3]++;
right++;
// 检查窗口是否满足条件
while (window[0] >= need[0] && window[1] >= need[1] && window[2] >= need[2] && window[3] >= need[3]) {
minLen = std::min(minLen, right - left);
// 缩小窗口
char d = input[left];
if (d == 'A') window[0]--;
else if (d == 'S') window[1]--;
else if (d == 'D') window[2]--;
else if (d == 'F') window[3]--;
left++;
}
}
- 初始化滑动窗口的左右边界
left和right都为 0,同时初始化最小子串长度minLen为输入字符串的长度n,并创建一个大小为 4 的整数向量window,用于统计当前滑动窗口内各个字符的频次。 - 在外部的
while循环中,不断扩展窗口(向右移动right指针),每次将新进入窗口的字符对应的window向量中的计数增加。 - 内部的
while循环用于检查当前窗口是否满足条件,即窗口内各个字符的频次是否都达到或超过了各自需要替换的次数(通过与need向量比较)。如果满足条件,就更新最小子串长度minLen为当前窗口长度(right - left)的最小值。然后尝试缩小窗口(向左移动left指针),将离开窗口的字符对应的window向量中的计数减少,继续寻找更小的满足条件的窗口。