📅  最后修改于: 2023-12-03 15:10:37.746000             🧑  作者: Mango
本题目中,给定一个数组和一个整数K,求该数组中最长的子数组,使得子数组中任意两个元素之间的差值不超过K。
一个很直观的思路是,对于每一个元素,向前或向后寻找最长的合法子数组,然后更新答案。但是这样的时间复杂度显然会很高($O(n^2)$)。
考虑将这个问题转化一下,将每个元素加上或减去至多K,使得最终的数组中所有元素相等。显然,最终数组的元素值一定是原数组的某个元素加上至多K或减去至多K得到的。因此只需要枚举数组中的每个元素,然后利用map记录元素值的出现次数,从而通过计算map中任意两个key之间的距离,得到以该元素为结尾的最长子数组。
具体来说,设当前枚举到的元素为$x$,当前最长子数组的起始下标为$i$,$map$表示元素值的出现次数,则更新最长子数组的步骤如下:
由于每个元素值只会在map中被加入或删除一次,因此总时间复杂度为$O(nlogn)$。
int longestSubarray(vector<int>& nums, int limit) {
int ans=1,n=nums.size();
map<int,int> mp;
int l=0,r=0;
mp[nums[0]]++;
while(r<n){
int maxn = mp.rbegin()->first,cnt = mp.rbegin()->second;
int minn = mp.begin()->first;
if(maxn-minn <= limit) ans=max(ans,r-l+1),r++;
else if(--mp[nums[l]]==0) mp.erase(nums[l]),l++;
if(r<n&&mp.count(nums[r])!=0) mp[nums[r]]++;
else if(r<n){
while(mp.size()){
if(abs(mp.begin()->first - nums[r]) <= limit){
mp[nums[r]]++,r++;
break;
}
if(--mp[nums[l]]==0) mp.erase(nums[l]),l++;
}
}
}
return ans;
}
注意:由于map中需要维护元素值的出现次数,因此需要检查$mp.count(nums[r])$是否为0,而不是简单地使用$mp[nums[r]]$。