【LeetCode】424. 替换后的最长重复字符 Longest Repeating Character Replacement(C++)


题目来源:https://leetcode-cn.com/problems/longest-repeating-character-replacement/

题目描述

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

注意:字符串长度 和 k 不会超过 10^4。

示例 1:

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

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

题目大意

  • 给定一个字符串,可使得区间内的字符进行替换K次,在执行完替换之后,找到包含重复字母的最长字串的长度,经典的双指针+滑动窗口题

双指针

  • 找到包含重复字母的最长字串的长度,最多需要进行k次替换,可转换题意,一个子串中最多可允许有k个不同的字符,并且求得此时的字串长度,注意在进行left向右滑动的过程中,无需更新此时区间[left, right]中字符出现的最多次数curMax
const int MAXN = 50;
int cnt[MAXN];
class Solution {
    
    
public:
    int characterReplacement(string s, int k) {
    
    
        memset(cnt, 0, sizeof(cnt));
        int left = 0, curMax = 0, ans = 0;
        int len = s.length();
        for(int right = 0 ; right < len ; ++right){
    
    
            int index = s[right] - 'A';
            ++cnt[index];
            if(cnt[index] >= curMax)
                curMax = cnt[index];
            while(curMax + k < right - left + 1){
    
    
                --cnt[s[left] - 'A'];
                ++left;
            }
            ans = max(ans, right - left + 1);
        }
        return ans;
    }
};

复杂度分析

  • 时间复杂度:O(n)。n为数组的长度,left和right均可视为滑动n次
  • 空间复杂度:O(n)。维护一个计数数组cnt作为全局变量

具体细节思考

  • 原先在没看官方题解之前,我手动维护了区间[left,right]中出现重复字符的最大次数,导致代码就算通过时间也有400ms,看了官方的解释和证明才恍然大悟
  • 此处引用官方题解所提出的问题和解释

maxCount 在内层循环「左边界向右移动一个位置」的过程中,没有维护它的定义,结论是否正确?

  • 答:结论依然正确。「左边界向右移动一个位置」的时候,maxCount 或者不变,或者值减 1。maxCount 的值虽然不维护,但数组 freq 的值是被正确维护的;
  • 当「左边界向右移动」之前:如果有两种字符长度相等,左边界向右移动不改变 maxCount 的值。例如 s = [AAABBB]、k = 2,左边界 A 移除以后,窗口内字符出现次数不变,依然为 3;
  • 如果左边界移除以后,使得此时 maxCount 的值变小,又由于 我们要找的只是最长替换 k 次以后重复子串的长度。接下来我们继续让右边界向右移动一格,有两种情况:
    • ① 右边界如果读到了刚才移出左边界的字符,恰好 maxCount 的值被正确维护;
    • ② 右边界如果读到了不是刚才移出左边界的字符,新的子串要想在符合题意的条件下变得更长,maxCount 一定要比之前的值还要更多,因此不会错过更优的解。

猜你喜欢

转载自blog.csdn.net/lr_shadow/article/details/113963254