题目
424. 替换后的最长重复字符
给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。
注意:字符串长度 和 k 不会超过 104。
示例 1:
输入:s = “ABAB”, k = 2
输出:4
解释:用两个’A’替换为两个’B’,反之亦然。
示例 2:
输入:s = “AABABBA”, k = 1
输出:4
解释:
将中间的一个’A’替换为’B’,字符串变为 “AABBBBA”。
子串 “BBBB” 有最长重复字母, 答案为 4。
思路
重要剖析:
k 个任意字符可以视为集五福中的万能福,left 就是窗口的左边。right 窗口的右边
整体思路就是用k个万能福构造一个大窗口,连续字符,只要不停向前扩展。如果实在不行了。就把左边的尾巴砍掉一截,如果没有找到更长的,我就类似平移。虽然出现次数最多的字母可能会变化,但是长度一直是在变大即可。
详细解析:
碰到统计大写字母次数的。直接把26个大小的数组建起来。(空间换时间,老套路了)
这个题目需要维护一个max变量,存一下当前窗口出现次数最多的字母的次数
看看哪个字母出现的最多,只有最多的 加上k 有可能会是最大的
从头开始遍历,遍历到一个那个字母个数+1
完后和max 取一下更大的。就是当前字符串中出现次数最多的那个字母的次数
如果+k 还是 不如当前字符串长度大,完了。这个k个万能福 也填不满你的空虚,你就缩一下吧。left++
并且减一下当前left那个字母的个数
继续向前扩展right++,如果k个万能福是填满的话,不用缩left, right继续向前!
最后返回 这个窗口的大小。
代码
private int[] map = new int[26];
public int characterReplacement(String s, int k) {
int left = 0;
int max = 0;
for (int right = 0;right < s.length();right++) {
int index = s.charAt(right) - 'A';
map[index]++;
max = Math.max(max, map[index]);
if (max + k < right - left + 1) {
map[s.charAt(left) - 'A']--;
left++;
}
}
return s.length() - left;
}
题目:
1004. 最大连续1的个数 III
给定一个由若干 0 和 1 组成的数组 A,我们最多可以将 K 个值从 0 变成 1 。
返回仅包含 1 的最长(连续)子数组的长度。
示例 1:
输入:A = [1,1,1,0,0,0,1,1,1,1,0], K = 2
输出:6
解释:
[1,1,1,0,0,1,1,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 6。
示例 2:
输入:A = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], K = 3
输出:10
解释:
[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 10。
提示:
1 <= A.length <= 20000
0 <= K <= A.length
A[i] 为 0 或 1
思路:
从头开始遍历,记录左端点left,右端点向前,如果遍历到0,0的个数加1,如果当前窗口内0的个数已经大于K,开始缩left,当 窗口内0的个数小于等于K,右端点再继续向前,记录窗口的大小的最大值
代码:
public int longestOnes(int[] A, int K) {
int res = 0;
int zeros = 0;
int left = 0;
int n = A.length;
for (int i = 0;i < n;i++) {
if (A[i] == 0) {
zeros++;
while (zeros > K) {
if (A[left++] == 0) {
zeros--;
}
}
}
res = Math.max(res, i - left + 1);
}
return res;
}
题目:
697. 数组的度
给定一个非空且只包含非负数的整数数组 nums,数组的度的定义是指数组里任一元素出现频数的最大值。
你的任务是在 nums 中找到与 nums 拥有相同大小的度的最短连续子数组,返回其长度。
示例 1:
输入:[1, 2, 2, 3, 1]
输出:2
解释:
输入数组的度是2,因为元素1和2的出现频数最大,均为2.
连续子数组里面拥有相同度的有如下所示:
[1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2]
最短连续子数组[2, 2]的长度为2,所以返回2.
示例 2:
输入:[1,2,2,3,1,4,2]
输出:6
提示:
nums.length 在1到 50,000 区间范围内。
nums[i] 是一个在 0 到 49,999 范围内的整数。
通过次数32,641提交次数57,959
思路:
数组效率高于map,首先求出来最大度数,采取数组
然后采用双指针滑动窗口的的方式,从左边开始向右滑,
使用map存储 出现元素的次数,和元素本身
如果当前遍历到的元素已经出现最大度数,求出当前窗口大小,并且左指针 向右滑,求出最短窗口的长度
代码:
public int findShortestSubArray(int[] nums) {
int[] arr = new int[50001];
int max = 0;
for (int i : nums) {
arr[i]++;
max = arr[i] > arr[max] ? i : max;
}
int l = 0,r = 0, len = nums.length, res = len + 1;
Map<Integer, Integer> map = new HashMap<>();
for (int right = 0; right < len;right++) {
map.put(nums[right], map.getOrDefault(nums[right], 0) + 1);
while (map.get(nums[right]) == arr[max]) {
res = Math.min(res, right - l + 1);
map.put(nums[l], map.get(nums[l]) - 1);
l++;
}
}
return res;
}