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

128 阅读1分钟

替换后的最长重复字符

题目描述

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

给你一个字符串 s 和一个整数 k 。你可以选择字符串中的任一字符,并将其更改为任何其他大写英文字符。该操作最多可执行 k 次。

在执行上述操作后,返回包含相同字母的最长子字符串的长度。

示例 1:

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

示例 2:

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

提示:

  • 1 <= s.length <= 105
  • s 仅由大写英文字母组成
  • 0 <= k <= s.length

题解

因为数据只有26个字符,所以可以先枚举目标字符串的字符是什么。第二重循环枚举左右端点,维护区间 [j,i][j, i] 中不等于最终目标字符的数量不超过操作数 kk ,可以用双指针去枚举一个端点,假设枚举右端点,当右端点 ii 确定后,考虑左端点最左能到达什么地方。

假设 jj 是满足区间 [j,i][j, i] 中不等于最终目标字符的数量不超过操作数 kk 最左的位置(也就是不等于最终目标字符的数量恰好等于操作数 kk ),再往左就不满足这个条件了。

我们可以发现,当 ii 单调向右走时,jj 也一定随着 ii 单调向右走,也就是 jjii 的一个单调函数,因此我们可以使用双指针算法。

反证法证明单调性:

定义 jj 是最靠左并且满足条件的位置,

假设当 ii 往右走到 ii'jj 往左走到 jj',满足区间 [j,i][j',i'] 中恰好有 kk 个不同的元素, 那么区间 [j,i][j',i] 中不等于目标字符的数量一定不超过 kk ,因为区间更小了,此时我们可以发现 jj 的位置与我们定义的矛盾,因为jj 可以再往左移动到 jj'。与假设矛盾,所以当 ii 往右走时,jj 一定不会往左走。

image-20221204231713714

代码

class Solution {
public:
    int characterReplacement(string s, int k) {
        // 维护区间[j, i]中不等于目标字符的数量不超过操作数k
        int res = 0;
        // 枚举目标字符
        for (char c = 'A'; c <= 'Z'; c++) {
            // cnt 记录窗口内等于目标字符的数量
            for (int i = 0, j = 0, cnt = 0; i < s.size(); i++) {
                if (s[i] == c) cnt++;
                // 如果窗口内不等于目标字符的数量大于k 则维护窗口直到满足这个条件
                while (i - j + 1 - cnt > k) {
                    // 窗口划出一个字符 如果划出字符是目标字符 则cnt--
                    if (s[j] == c) cnt--;
                    j++;
                }
                res = max(res, i - j + 1);
            }
        }
        return res;
    }
};