leetcode424.替换后的最长重复字符

题目大意

给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。

注意:
字符串长度 和 k 不会超过 104。

示例 1:

输入:
s = "ABAB", k = 2
输出:
4
解释:
用两个'A'替换为两个'B',反之亦然。

示例 2:

输入:
s = "AABABBA", k = 1
输出:
4
解释:
将中间的一个'A'替换为'B',字符串变为 "AABBBBA"。
子串 "BBBB" 有最长重复字母, 答案为 4

解题思路

我们的目标是计算以位置i字符结尾时,当前的最长重复字符(重复字符不一定是s[i],只是说变换k次后,最长重复字符串以i位置为结尾)。遍历s,得到以每个位置为结尾时的最长重复字符,取最大值即可。

这道题采用滑动窗口方法来做。

当前窗口左端点为left,右端点为right,计算窗口中出现次数最多的字符数量tmp,窗口长度为l=right-left+1,如果l-tmp>k,表示在窗口中替换k次后,仍然不能统一窗口中的字符,因此窗口需要缩小,left+1。反之,则以right位置为结尾的最长重复字符就是窗口的长度。

计算完right位置后,right+1,计算下一个位置。

注意:代码中窗口左端点收缩后,并没有重新计算当前窗口中的字符出现频次最大值(也不需要重新计算):当给定curMaxCount和k后,隐含了一个条件,即最大结果就是curMaxCount+k(某个字符出现了curMaxCount次,将其它k个字符换成该字符,即最长重复)。

所以,右端点扩展后,如果窗口中右端点right的数量没有大于当前curMaxCount,则说明以right位置为结尾的最长重复字符结果不会大于上一轮的结果。

class Solution {
public:
    int characterReplacement(string s, int k) {
    	// 能够将s中所有字符统一
    	if (s.size() - 1 <= k)
    		return s.size();
		// s中全部是大写字母,因此用26长度的数组记录窗口元素的出现频次
    	vector<int> nums(26, 0);
		// 分别是:左端点、右端点、最终结果、当前窗口出现频次的最大值
    	int left = 0, right = 0, res = 0, curMaxCount = 0;

    	for (; right < s.size(); ++right){
    		// right位置元素进入窗口,数组中记录信息
    		++nums[s[right] - 'A'];
    		// 相较于上一次的窗口,仅多了一个right位置元素
    		// 因此当前窗口最大值只需要跟s[right]的数量比较一下就行
    		curMaxCount = max(curMaxCount, nums[s[right] - 'A']);
			
			// 替换K次后,仍然不能统一窗口元素,则窗口收缩(left+1)
    		while (right - left + 1 - curMaxCount > k)
    			// 窗口元素出去一个,对应的数组中-1
    			--nums[s[left++] - 'A'];

    		res = max(res, right - left + 1);
    	}
    	return res;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_41092190/article/details/106437728