[LeetCode] 424. Longest Repeating Character Replacement

You are given a string s and an integer k. You can choose any character of the string and change it to any other uppercase English character. You can perform this operation at most k times.

Return the length of the longest substring containing the same letter you can get after performing the above operations.

Example 1:

Input: s = "ABAB", k = 2
Output: 4
Explanation: Replace the two 'A's with two 'B's or vice versa.

Example 2:

Input: s = "AABABBA", k = 1
Output: 4
Explanation: Replace the one 'A' in the middle with 'B' and form "AABBBBA".
The substring "BBBB" has the longest repeating letters, which is 4.

Constraints:

  • 1 <= s.length <= 105
  • s consists of only uppercase English letters.
  • 0 <= k <= s.length

替换后的最长重复字符。

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

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

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-repeating-character-replacement
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题意是给一个字符串,只有大写字母,允许你替换其中的 K 个字母,问替换操作完成后能返回的最长字母相同的子串的长度是多少。既然是看替换K个字母之后能组成的相同字母的子串的长度,所以思路还是偏向滑动窗口。那么替换字母的原则应该是先统计目前每个不同字母的出现次数,然后用 K 尽量去替换成那个出现最多次数的字母,看看是否能组成最长的子串。具体做法如下

  • 创建一个 map 记录 s 中每个字母和他们的出现次数
  • 创建两个指针 start 和 end 准备卡住窗口
  • end 先移动,并同时用一个变量 max 找到当下最大的出现次数
  • 如果当前窗口 size - K > max,则考虑缩小窗口尺寸,挪动 start 指针
  • 窗口 size 缩减到小于 max + K 之后,记录一个当前窗口的值,这个值就是替换了 K 个字符之后能组成的最长重复子串的长度

这个题我在做的时候有个疑问,为什么通过滑动窗口找到的这个最长子串的长度是对的呢?我举了个反例,比如 s 是 ABCDEFGA好了,K = 2,出现次数最多的字母依然是 A。按照上面的算法,直到扫到 input 的最后才会发现出现次数最多的字母是 A,既然 K 是 2,所以无论你替换别的任何字母,最后跟 A 凑成最长的子串都一定是 1 + 2 = 3,因为前后两个 A 是凑不到一起的。

这个例子只能证明滑动窗口可以解决这道题,并没有回答另一个疑问:最长的子串里面一定包含出现次数最多的字母,这个没有什么疑问。但是左指针在往前走,试图缩短窗口尺寸的时候,会不会造成额外的问题?答案是不会。我参考了这个帖子。右指针停下的位置一定是当前出现次数最多的字母的位置。如果此时左指针开始往前走(试图缩短窗口尺寸),虽然随着左指针往前走,出现次数最多的字母的次数(最多次数)会被减少,但是并不影响这个字母是出现次数最多的字母的事实。目前需要找的窗口大小依然是基于这个出现次数最多的字母而找的。

第三个疑问是按照代码里跑的方式,start 和 end 指针中间也许不会包含出现次数最多的那个字母所有出现的地方,比如我们发现 max = 5,但是 start 和 end 之间也许并不会包含那个字母 5 次,这种情况下,代码是让 start 和 end 指针同时往前走的,只要两个指针的距离没变,结果就是对的。

时间O(n)

空间O(1) - 一个26位长度的数组

Java实现

 1 class Solution {
 2     public int characterReplacement(String s, int k) {
 3         int[] map = new int[128];
 4         int start = 0;
 5         int end = 0;
 6         int res = 0;
 7         int max = 0;
 8         while (end < s.length()) {
 9             char c1 = s.charAt(end);
10             map[c1]++;
11             end++;
12             max = Math.max(max, map[c1]);
13             if (end - start - max > k) {
14                 char c2 = s.charAt(start);
15                 map[c2]--;
16                 start++;
17             }
18             res = Math.max(res, end - start);
19         }
20         return res;
21     }
22 }

 

JavaScript实现

 1 /**
 2  * @param {string} s
 3  * @param {number} k
 4  * @return {number}
 5  */
 6 var characterReplacement = function(s, k) {
 7     let count = {};
 8     let start = 0;
 9     let max = 0;
10     let res = 0;
11     for (let end = 0; end < s.length; end++) {
12         count[s[end]] = count[s[end]] + 1 || 1;
13         max = Math.max(max, count[s[end]]);
14         if (end - start + 1 - max > k) {
15             count[s[start]]--;
16             start++;
17         }
18         res = Math.max(res, end - start + 1);
19     }
20     return res;
21 };

 

sliding window相关题目

LeetCode 题目总结

posted @ 2020-04-04 01:21  CNoodle  阅读(155)  评论(0编辑  收藏  举报