给你一个下标从 0 开始的整数数组 nums
和一个整数 k
。
如果子数组中所有元素都相等,则认为子数组是一个 等值子数组 。注意,空数组是 等值子数组 。
从 nums
中删除最多 k
个元素后,返回可能的最长等值子数组的长度。
子数组 是数组中一个连续且可能为空的元素序列。
示例 1:
输入:nums = [1,3,2,3,1,3], k = 3
输出:3
解释:最优的方案是删除下标 2 和下标 4 的元素。
删除后,nums 等于 [1, 3, 3, 3] 。
最长等值子数组从 i = 1 开始到 j = 3 结束,长度等于 3 。
可以证明无法创建更长的等值子数组。
示例 2:
输入:nums = [1,1,2,2,1,1], k = 2
输出:4
解释:最优的方案是删除下标 2 和下标 3 的元素。
删除后,nums 等于 [1, 1, 1, 1] 。
数组自身就是等值子数组,长度等于 4 。
可以证明无法创建更长的等值子数组。
提示:
·1 <= nums.length <= 105
·1 <= nums[i] <= nums.length
·0 <= k <= nums.length
题目大意:计算最多删除k个元素的情况下数组中最长等值子数组的长度。
分析:设区间[i,j]中众数的个数为maxCount。
(1)区间[i,j]中的最长等值子数组长度<=区间[i-1,j]中的最长等值子数组长度;
(2)由(1)可知,当区间右端点j确定时,左端点i越小越好。又因为最多只能删除k个元素,因此当j确定时,i的最小值是固定的,即i在最小处时,数组i-1号元素不等于区间[i,j]中的众数,且j-i+1-maxCount==k;
(3)由(2)可知,可利用滑动窗口,不断向右移动窗口右端点j,当j-i+1-maxCount==k+1时,向右移动窗口左端点i,同时在移动滑动窗口过程中维护maxCount的值即可;
(4)设右端点j对应的最小左端点为i,右端点n对应的最小左端点为m,区间[i,j]的众数个数为maxCount1,区间[m,n]的众数个数为maxCount2,由(2)中结论可知j-i+1=k+maxCount1,n-m+1=k+maxCount2。因此当maxCount2>maxCount1时,n-m>j-i,所以maxCount越大,窗口的长度越长;
(5)由于在遍历过程中要获取最大的maxCount,根据(4)中结论,只需维护最大的maxCount即可,当前右端点对应的区间长度也只需保持为出现过的最长区间长度,只有当更大的maxCount出现时,才会扩大区间。因为当前区间的众数个数若无法超越maxCount,即使区间长度可能大于其本应设置的长度,但由于区间长度并未超越出现过的最长区间的长度,对于maxCount的值并不会产生影响。
class Solution {
public:int longestEqualSubarray(vector<int>& nums, int k) {int N=nums.size(),size=0,maxCount=0;unordered_map<int,int> map;for(int l=-1,r=0;r<N;++r){maxCount=max(maxCount,++map[nums[r]]);//根据maxCount的大小更新区间范围if(++size-maxCount==k+1){--size;--map[nums[++l]];}}return maxCount;}
};