题目链接:www.marscode.cn/practice/w7…
题目的要求是通过替换一个最小长度的连续子串,使得替换后整个字符串中 A、S、D、F 四个字符的出现次数相等。注意,题目不要求这个连续子串中的所有字符都被替换。
双指针 + 滑动窗口
代码
时间复杂度:。
空间复杂度:。
#include <iostream>
#include <string>
#include <array>
#include <algorithm>
using namespace std;
inline int charToIndex(const char c) {
switch (c) {
case 'A': return 0;
case 'S': return 1;
case 'D': return 2;
default: return 3;
}
}
int solution(string input) {
const int length = static_cast<int>(input.size());
const int targetFrequency = length >> 2; // 每个字符应该出现的理想次数
// 计算多余数量,按理来说没有超过的targetFrequency的字符对应的excess值为0,但为负数也不会影响代码的正确性
array<int, 4> excess;
fill(excess.begin(), excess.end(), -targetFrequency);
for (const char &ch: input) {
++excess[charToIndex(ch)];
}
// 不需要替换时每个字符的excess值为0
if (excess[0] == 0 and excess[1] == 0 and excess[2] == 0 and excess[3] == 0) {
return 0;
}
// 滑动窗口,寻找最短子串
array<int, 4> currentWindow;
fill(currentWindow.begin(), currentWindow.end(), 0);
int left = 0;
int minimalSubstringLength = length;
for (int right = 0; right < length; ++right) {
// 扩大窗口
++currentWindow[charToIndex(input[right])];
// 当窗口满足包含所有多余字符数量时,尝试缩小窗口
while (currentWindow[0] >= excess[0] and currentWindow[1] >= excess[1] and
currentWindow[2] >= excess[2] and currentWindow[3] >= excess[3]) {
// 更新最短子串长度
minimalSubstringLength = min(minimalSubstringLength, right - left + 1);
// 缩小左边界
--currentWindow[charToIndex(input[left])];
++left;
}
}
return minimalSubstringLength;
}
int main() {
cout << (solution("ADDF") == 1) << endl;
cout << (solution("ASAFASAFADDD") == 3) << endl;
cout << (solution("SSDDFFFFAAAS") == 1) << endl;
cout << (solution("AAAASSSSDDDDFFFF") == 0) << endl;
cout << (solution("AAAADDDDAAAASSSS") == 4) << endl;
return 0;
}
思路
统计每个字符的excess值,如果为全0,则不需要替换;否则用左右指针 [left, right] 做滑动窗口,去寻找最短的一个子串,使得这个子串中至少包含这四种字符多余的数量。当满足条件后,就尝试收缩 left 以找更短的子串。