Marscode T41 滑动窗口算法
滑动窗口是一种常用的算法技巧,特别适用于在数组或字符串中寻找满足特定条件的子数组或子串.
问题概述
小F得到了一个特殊的字符串,这个字符串只包含字符A、S、D、F,其长度总是4的倍数。他的任务是通过尽可能少的替换,使得A、S、D、F这四个字符在字符串中出现的频次相等。求出实现这一条件的最小子串长度。
测试样例
输入:input = "ADDF" 输出:1
输入:input = "ASAFASAFADDD" 输出:3
输入:input = "SSDDFFFFAAAS" 输出:1
代码
javascript
function solution(input) {
let countA = 0, countS = 0, countD = 0, countF = 0;
for (let char of input) {
if (char === 'A') countA++;
else if (char === 'S') countS++;
else if (char === 'D') countD++;
else if (char === 'F') countF++;
}
const targetCount = input.length / 4;
const excessA = Math.max(0, countA - targetCount);
const excessS = Math.max(0, countS - targetCount);
const excessD = Math.max(0, countD - targetCount);
const excessF = Math.max(0, countF - targetCount);
if (countA === targetCount && countS === targetCount && countD === targetCount && countF === targetCount) {
return 0;
}
// 滑动窗口的左右边界
let left = 0, right = 0;
let minLength = input.length; // 初始化最小长度为整个字符串的长度
// 滑动窗口内的字符计数
let windowCountA = 0, windowCountS = 0, windowCountD = 0, windowCountF = 0;
// 扩展右边界
while (right < input.length) {
// 更新窗口内的字符计数
if (input[right] === 'A') windowCountA++;
else if (input[right] === 'S') windowCountS++;
else if (input[right] === 'D') windowCountD++;
else if (input[right] === 'F') windowCountF++;
// 尝试收缩左边界
while (windowCountA >= excessA && windowCountS >= excessS && windowCountD >= excessD && windowCountF >= excessF) {
// 更新最小长度
minLength = Math.min(minLength, right - left + 1);
// 更新窗口内的字符计数
if (input[left] === 'A') windowCountA--;
else if (input[left] === 'S') windowCountS--;
else if (input[left] === 'D') windowCountD--;
else if (input[left] === 'F') windowCountF--;
// 移动左边界
left++;
}
// 移动右边界
right++;
}
return minLength;
}
function main() {
// You can add more test cases here
console.log(solution("ADDF") === 1);
console.log(solution("ASAFASAFADDD") === 3);
}
main();
思路
理解问题:
题目要求我们通过尽可能少的替换操作,使得字符串中字符A、S、D、F的出现频次相等。 字符串的长度总是4的倍数,因此每个字符的目标频次是input.length / 4
。
计算每个字符的频次:
遍历字符串,统计每个字符A、S、D、F的出现次数。
计算每个字符的“多余”数量:
对于每个字符,计算其超出目标频次的数量(即excess)。如果某个字符的频次已经达到目标频次,则其excess为0。
使用滑动窗口寻找最小子串:
- 使用滑动窗口(双指针)技术来寻找一个最小的子串,使得该子串中包含足够多的“多余”字符,以便通过替换操作使得整个字符串的频次达到平衡。
- 初始化左右指针left和right,并维护一个窗口内的字符计数。
- 扩展右指针right,直到窗口内的字符计数满足所有字符的excess要求。
- 一旦满足条件,尝试收缩左指针left,以找到最小的满足条件的子串。
- 更新最小子串的长度,并继续移动右指针,直到遍历完整个字符串。
返回结果:
最终返回找到的最小子串的长度,即为所需的最少替换操作次数。