题目:
给定整数数组 A,每次 move 操作将会选择任意 A[i],并将其递增 1。
返回使 A 中的每个值都是唯一的最少操作次数。
示例 1:
输入:[1,2,2]
输出:1
解释:经过一次 move 操作,数组将变为 [1, 2, 3]。
示例 2:
输入:[3,2,1,2,1,7]
输出:6
解释:经过 6 次 move 操作,数组将变为 [3, 4, 1, 2, 5, 7]。
可以看出 5 次或 5 次以下的 move 操作是不能让数组的每个值唯一的。
提示:
0 <= A.length <= 40000
0 <= A[i] < 40000
解法:
// Solution One -- 排序后,把后面小于等于前面的数变成比前一个数大一;156ms 40.8mb
// 时间、空间复杂度: O(n)
var minIncrementForUnique0 = function(A) {
let len = A.length
if(len <= 1) return 0
A.sort((a,b) => {return a-b})
let count = 0
for(let i = 1; i < len; i++){
if(A[i] <= A[i-1]){
count += A[i-1] - A[i] + 1
A[i] = A[i-1] + 1
}
}
return count
};
// Solution Two -- 官方1 计数 152ms 78.2mb
/*
复杂度分析
时间复杂度:O(L)O(L),其中 LL 的数量级是数组 A 的长度加上其数据范围内的最大值,因为在最坏情况下,数组 A 中的所有数都是数据范围内的最大值。
空间复杂度:O(L)O(L),需要长度 LL 的数组统计每个数出现的次数。
*/
var minIncrementForUnique1 = function(A) {
let countArr = new Array(80000)
for(let num of A){
if(!countArr[num]){
countArr[num] = 1
}else{
countArr[num] += 1
}
}
let count = 0, taken = 0
for(let i = 0; i < 80000; i++){
if(countArr[i] && countArr[i] >= 2){
taken += countArr[i] - 1
count -= i * (countArr[i] - 1)
}else if(taken > 0 && (countArr[i] === 0 || !countArr[i])){
taken--
count += i
}
}
return count
};
// Solution Three -- 官方2 排序 156ms 40.7mb
/*
复杂度分析
时间复杂度:O(N\log N)O(NlogN),其中 NN 是数组 AA 的长度,即排序的时间复杂度。
空间复杂度:O(\log N)O(logN),排序需要额外 O(\log N)O(logN) 的栈空间。
*/
var minIncrementForUnique2 = function(A) {
let len = A.length
if(len <= 1) return 0
A.sort((a,b) => {return a-b})
let count = 0, taken = 0, give = 0
for(let i = 1; i < len; i++){
if(A[i-1] === A[i]){
taken++
count -= A[i]
}else{
give = Math.min(taken, A[i] - A[i-1] - 1)
count += give * (give + 1)/2 + give * A[i-1]
taken -= give
}
}
count += taken * (taken + 1)/2 + taken * A[A.length - 1]
return count
};