题目:
给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。
注意:字符串长度 和 k 不会超过 104。
解题思路:
本题利用双指针+滑动窗口的方法进行求解。
初始窗口的宽度为 1
,我们不断的通过向当前窗口覆盖的子串后面追加一个字符看是否能满足我们的要求,那么如何判断该字符串是否满足我们的要求:
如果当前字符串中的出现次数最多的字母个数 +K大于串长度,那么这个串就是满足条件的;
我们维护一个数组 int[26] 来存储当前窗口中各个字母的出现次数,left 表示窗口的左边界,right 表示窗口右边界;historyCharMax 保存滑动窗口内相同字母出现次数的 历史 最大值,通过判断窗口宽度 (right - left + 1)是否大于 historyCharMax + K 来决定窗口是否做滑动,否则窗口就扩张。
窗口扩张:left 不变,right++;
窗口滑动:left++,right++;
核心要点:
1、map记录的是【窗口里的】字符出现的次数,是窗口里的!窗口里的!所以左窗口右移后,记得将移出去的元素个数-1
2、我们的目的就是让窗口尽可能扩张,有K个字符的容错机会,容错机会肯定要用给map中出现次数最多的字符才有机会让窗口扩张
3、就算某一刻你发现框里元素都不一样,但不要怀疑,因为它曾经辉煌过,它会一直呈现它窗口最大时候的状态
代码示例:
public int characterReplacement(String s, int k) {
int[] map = new int[26];
int n = s.length(), left = 0, right = 0, maxChar = 0;
char[] chars = s.toCharArray();
for (; right < n; right++) {
int m = chars[right] - 'A';
map[m]++;
maxChar = Math.max(maxChar, map[m]);
if (right - left + 1 > maxChar + k) {
map[chars[left] - 'A']--;
left++;
}
}
return n - left;
}