Medium
题目描述
给你一个整数数组 nums 和一个整数 k。
你可以对数组中的每个元素最多执行一次以下操作:
- 给元素加上范围
[-k, k]内的任意整数。
返回执行操作后 nums 中可能的最大不同元素数量。
示例 1:
输入:nums = [1,2,2,3,3,4], k = 2
输出:6
解释:
前四个元素执行操作后,nums 变为 [-1, 0, 1, 2, 3, 4]。
示例 2:
输入:nums = [4,4,4,4], k = 1
输出:3
解释:
通过给 nums[0] 加 -1,给 nums[1] 加 1,nums 变为 [3, 5, 4, 4]。
提示:
1 <= nums.length <= 10^51 <= nums[i] <= 10^90 <= k <= 10^9
解题思路
这道题的关键在于理解每个元素可以调整到的范围是 [nums[i]-k, nums[i]+k],我们需要为每个元素分配一个在其调整范围内的值,使得最终的不同元素数量最大。
贪心策略
最优的策略是使用贪心算法:
- 首先将数组排序,这样相邻的元素原始值比较接近,便于统一处理
- 对于每个元素,尽量选择其调整范围内最小的可用值
- 维护一个"下一个可用值",确保每次分配的值都是不重复的
具体算法
- 排序后,对于第一个元素,选择其调整范围的最小值
nums[0]-k - 对于后续元素
nums[i],其可选范围是[nums[i]-k, nums[i]+k] - 在这个范围内选择不小于"下一个可用值"的最小值
- 如果范围内没有可用值,则跳过该元素
- 更新"下一个可用值"为已选值+1
通过这种贪心策略,我们可以确保每个元素都获得其范围内最优的值分配,从而最大化不同元素的数量。时间复杂度主要来自排序操作。
代码实现
class Solution {
public:
int maxDistinctElements(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());
long long nextAvailable = nums[0] - k;
int count = 1;
for (int i = 1; i < nums.size(); i++) {
long long minVal = nums[i] - k;
long long maxVal = nums[i] + k;
if (nextAvailable + 1 <= maxVal) {
nextAvailable = max((long long)(nextAvailable + 1), minVal);
count++;
}
}
return count;
}
};
class Solution:
def maxDistinctElements(self, nums: List[int], k: int) -> int:
nums.sort()
next_available = nums[0] - k
count = 1
for i in range(1, len(nums)):
min_val = nums[i] - k
max_val = nums[i] + k
if next_available + 1 <= max_val:
next_available = max(next_available + 1, min_val)
count += 1
return count
public class Solution {
public int MaxDistinctElements(int[] nums, int k) {
Array.Sort(nums);
long nextAvailable = nums[0] - k;
int count = 1;
for (int i = 1; i < nums.Length; i++) {
long minVal = nums[i] - k;
long maxVal = nums[i] + k;
if (nextAvailable + 1 <= maxVal) {
nextAvailable = Math.Max(nextAvailable + 1, minVal);
count++;
}
}
return count;
}
}
var maxDistinctElements = function(nums, k) {
nums.sort((a, b) => a - b);
let nextAvailable = nums[0] - k;
let count = 1;
for (let i = 1; i < nums.length; i++) {
const minVal = nums[i] - k;
const maxVal = nums[i] + k;
if (nextAvailable + 1 <= maxVal) {
nextAvailable = Math.max(nextAvailable + 1, minVal);
count++;
}
}
return count;
};
复杂度分析
| 复杂度类型 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 贪心算法 | O(n log n) | O(1) |
- 时间复杂度:O(n log n),主要来自排序操作,遍历数组为 O(n)
- 空间复杂度:O(1),只使用常数级别的额外空间(不考虑排序的空间开销)