昨晚力扣双周赛的第三题据说是根据这题改的,反正昨晚是没做出来,想着或许是dp,或许是前缀和,没想到是用双指针和滑动窗口(话说今天看题解都看了半天,跟我说用滑动窗口我也不一定做的出来。。)
题目描述:
给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。
方法一:
class Solution {
public:
int characterReplacement(string s, int k) {
int n = s.size();
int left = 0; //左指针
int right = 0; //右指针
int maxn = 0; //窗口内最长的重复字母
vector<int> nums(26); //记录窗口内每个字母出现的次数
while (right < n)
{
int index = s[right] - 'A';
nums[index]++; //右指针新指向的字母的出现次数加一
maxn = max(maxn, nums[index]); //更新窗口内最长的重复字母
if (right - left + 1 > maxn + k)
{
nums[s[left] - 'A']--;
left++;
}
right++;
}
return right - left;
}
};
这道题需要转换一下题目描述,改成:求字符串中的这么一个最长区间,区间内除了最多的重复字符外,其他字符的个数不超过k个(也就是说,其他字符可以全都替换成这个最多的重复字符)。
这么一改,题目就比原来好懂了,不是让我们一个一个地替换字符然后求最长的重复字符串,而是求这么一个符合要求的区间,而说到求区间,又容易想到用双指针、滑动窗口的方法。
具体方法还是看官方题解及下方的评论吧,比较详细。
我说说我的理解:
由于需要求的是一个最长的区间,所以这个滑动窗口的长度设置为或者增大或者不变。
maxn记录的是出现过的最长重复字符,当maxn发生变化即变大时,滑动窗口的大小就要马上增大到maxn + k + 1的长度;当maxn不变时,那么就保持滑动窗口的大小向右继续移动。这么一来遍历完之后,right - left的大小(在遍历时,由于right多加了一次1,所以这里不是right + left + 1)就是所求的区间的最长长度。