给你一个整数数组
nums
和一个整数k
。你可以对数组中的每个元素 最多 执行 一次以下操作:
- 将一个在范围
[-k, k]
内的整数加到该元素上。返回执行这些操作后,
nums
中可能拥有的不同元素的 最大数量。示例 1:
输入: nums = [1,2,2,3,3,4], k = 2
输出: 6
解释:
对前四个元素执行操作,
nums
变为[-1, 0, 1, 2, 3, 4]
,可以获得 6 个不同的元素。示例 2:
输入: nums = [4,4,4,4], k = 1
输出: 3
解释:
对
nums[0]
加 -1,以及对nums[1]
加 1,nums
变为[3, 5, 4, 4]
,可以获得 3 个不同的元素。提示:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^9
0 <= k <= 10^9
思路
这道题目中的 [-k, k]
很有迷惑性,你不能去细想该怎么给哪个数加多少,一旦陷入这种细节之中思路就会混乱,而且这题暴力模拟是会超时的,今天我就是想复杂了导致原地坐牢
贪心的想,既然题目都说了可以让每个数加上 [-k, k]
中的任意一个数,我们要尽可能的腾出更多的位置去放相同的那些数,就让小的数加上最小值-k呗,然后次小的数就要根据 前一个数的具体数值来决定了
具体的说,将数组按照从小到大的顺序排序,对第一个数来说,直接让nums[0]=nums[0]-k即可
对于第二个数
1.如果第一个数第二个不同,那么nums[1]同样可以等于nums[1]-k
2.如果第一个数和第二个数相同,那么nums[1]不能等于nums[1]-k,因为它已经被第一个数占用了,那就贪心的退而求其次,让它等于修改后的nums[0]+1
但是这个规则无法适用于整体,像上面题目中的样例2, 4 4 4 4,第一个数变成3,第二个数就变成3+1,第三个数变成3+1+1,但是第四个数没法变成 3+1+1+1,因为k=1,4最多可以变成5
所有需要判断一下(前 一个数+1)是否大于 (当前数+k),取两者之间的较小值
具体的说,定义一个变量pre记录前一个符合条件的数的值,初始化为无限小
遍历排过序之后的数组,如果nums[i]-k大于pre,那么当前数就可以变成nums[i]-k,否则判断前一个数加一是否超出当前数可以表示的范围(nums[i]+k),如果超出的话当前数字就要舍弃
代码
java
class Solution {
public int maxDistinctElements(int[] nums, int k) {
Arrays.sort(nums);
int ans=0;
int pre=Integer.MIN_VALUE;
for(int i=0;i<nums.length;i++){
//(nums[i]-k)已被占用
if(nums[i]-k<=pre){
//退而求其次,贪心的将当前数变成前一个数+1
//如果pre+1大于nums[i]+k就不符合条件,直接判断下一个数
if(pre+1>nums[i]+k)
continue;
nums[i]=pre+1;
}else{
//nums[i]-k未被占用,贪心的将当前数变小
nums[i]=nums[i]-k;
}
pre=nums[i];
ans++;
}
return ans;
}
}