leetcode 2779. 数组的最大美丽值
暴力超时解🤡
class Solution {
public:
int maximumBeauty(vector<int>& nums, int k) {
int size = nums.size(),res = 0;
unordered_map<int,int> numCount;
for(int i = 0;i < size;++i){
for(int j = nums[i] - k;j <= nums[i] + k;++j){
++numCount[j];
res = max(res,numCount[j]);
}
}
return res;
}
};
法一:差分数组1,考虑所以情况,放到numCount内
class Solution {
public:
int maximumBeauty(vector<int>& nums, int k) {
int size = nums.size(),res = 0;
int numCount[300001]{};
for(int i = 0;i < size;++i){
++numCount[nums[i]-k+100000];
if(nums[i]+k+1<200000) --numCount[nums[i]+k+1+100000];
}
for(int i = 1;i < 300001;++i){
numCount[i] += numCount[i-1];
res = max(res,numCount[i]);
}
return res;
}
};
法一:差分数组2,nums[i] < k 都当作是 0 , nums[i] + k + 1 > 差分数组右边界 都当作是右边界
class Solution {
public:
int maximumBeauty(vector<int>& nums, int k) {
int maxNum = *max_element(nums.begin(),nums.end());
int size = nums.size();
vector<int> diff(maxNum+2);
for(int i = 0;i < size;++i){
++diff[max(nums[i] - k , 0)];
--diff[min(nums[i] + k + 1 , maxNum + 1)];
}
int res = diff[0];
for(int i = 1;i < maxNum + 2;++i){
diff[i] += diff[i-1];
res = max(res,diff[i]);
}
return res;
}
};
或者
class Solution {
public:
int maximumBeauty(vector<int>& nums, int k) {
int maxNum = *max_element(nums.begin(),nums.end());
vector<int> diff(maxNum+2);
for(int & num : nums){
++diff[max(num - k , 0)];
--diff[min(num + k + 1 , maxNum + 1)];
}
int res = 0,accum = 0;
for(int &num : diff){
accum += num;
res = max(res,accum);
}
return res;
}
};
法二:排序+滑动窗口
leetcode官方解析:
根据题目对子序列的定义,我们知道元素的顺序对数组的美丽值无影响,因此我们先对数组 nums 进行排序。
假设数组的最大美丽值对应的相等元素为 x,那么经过任意操作后,可以变为 x 的元素范围为 [x−k,x+k],对应排序后数组的一个连续子数组。
因此题目等价于找到最大最小值之差小于等于 2k 的最长连续子数组,该子数组的长度即为数组的最大美丽值。
我们使用滑动窗口的方法来解决,令某连续子数组的右端点为 i,左端点为 j,初始时都为 0,我们依次枚举右端点 i:为了使 nums[i]−nums[j]≤2k,我们不断地右移左端点 j 直到 nums[i]−nums[j]≤2k 成立,那么右端点 i 对应的最大最小值之差小于等于 2k 的最长连续子数组的长度为 i−j+1。
最后返回这些长度的最大值为数组的最大美丽值。
class Solution {
public:
//题目要求的「由相等元素组成的最长子序列」,相当于选出若干闭区间,这些区间的交集不为空。
//排序后,选出的区间是连续的,我们只需考虑最左边的区间 [x−k,x+k] 和最右边的区间 [y−k,y+k]
//如果这两个区间的交集不为空,那么选出的这些区间的交集就不为空。也就是说,要满足 x+k ≥ y−k,即 y−x ≤ 2k
//原题等价于:排序后,找最长的连续子数组,其最大值减最小值 ≤ 2k。数组有序,相当于子数组的最后一个数减去子数组的第一个数 ≤ 2k。
//只要子数组满足这个要求,对应的区间的交集就不为空,也就是子数组的元素都可以变成同一个数。
//枚举 nums[right] 作为子数组的最后一个数,一旦 nums[right] − nums[left] > 2k,就移动左端点 left。
//左端点停止移动时,下标在 [left,right] 的子数组就是满足要求的子数组,用子数组长度 right − left + 1 更新答案的最大值。
int maximumBeauty(vector<int>& nums, int k) {
sort(nums.begin(),nums.end());
int res = 0,size = nums.size(),left = 0;
for(int right = 0;right < size;++right){
while(nums[right] - nums[left] > 2*k) ++left;
res = max(res,right-left+1);
}
return res;
}
};