给定整数数组 A,每次 move 操作将会选择任意 A[i],并将其递增 1。
返回使 A 中的每个值都是唯一的最少操作次数。
示例 1:
输入:[1,2,2]
输出:1
解释:经过一次 move 操作,数组将变为 [1, 2, 3]。
提示:
0 <= A.length <= 400000 <= A[i] < 40000
计数
对原数组一次便利,用新数组来记录每个值出现的次数。循环这个新的数组,对每一个元素进行:
- 如果当前元素的数量等于一个,不处理
- 如果当前元素数量超过了1个,那么需要将多余的数字给剔除掉。记录下剔除的数量 token 和剔除的总和
- 如果当前元素的数量为0,且在此之前已经有过剔除,那么这个数字就是我们需要新增的数字。即 taken-1,ans+=这个数字
这个ans就是我们最终需要增加的数总和。
public int minIncrementForUnique(int[] A) {
// 因为题目明确了A的最大值为40000,那么在最极限的情况下给的测试用例为40000个40000,那么最终结果数组需要有40000~80000,所以数组数量设定为80000
int[] arr = new int[80000];
for(int i=0;i<A.length;i++){
arr[A[i]]++;
}
int taken=0,res=0;
for(int i=0;i<arr.length;i++){
if(arr[i] > 1){
taken += arr[i] - 1;
res -= i * (arr[i] - 1);
}else if(taken > 0 && arr[i] == 0){
taken--;
res += i;
}
}
return res;
}
- 时间复杂度:O(L) 其中 LL 的数量级是数组 A 的长度加上其数据范围内的最大值,因为在最坏情况下,数组 A 中的所有数都是数据范围内的最大值
- 空间复杂度:O(L) 需要长度 LL 的数组统计每个数出现的次数
排序
对数组进行一次排序后,对每一个元素,保持这个元素比上一个元素至少大于1即可。
public int minIncrementForUnique(int[] A) {
Arrays.sort(A);
int res = 0;
for(int i=1;i<A.length;i++){
if(A[i] <= A[i-1]) {
res += A[i-1] - A[i] + 1;
A[i] = A[i-1] + 1;
}
}
return res;
}
- 时间复杂度:O(nlogn) 排序+一次遍历
- 空间复杂度:O(logn) 排序需要logn级的栈空间