【LeetCode-945】使数组唯一的最小增量
问题
给定整数数组 A,每次 move 操作将会选择任意 A[i],并将其递增 1。
返回使 A 中的每个值都是唯一的最少操作次数。
0 <= A.length <= 40000
0 <= A[i] < 40000
示例
输入:[1,2,2]
输出:1
解释:经过一次 move 操作,数组将变为 [1, 2, 3]。
输入:[3,2,1,2,1,7]
输出:6
解释:经过 6 次 move 操作,数组将变为 [3, 4, 1, 2, 5, 7]。可以看出 5 次或 5 次以下的 move 操作是不能让数组的每个值唯一的。
解答1:排序(O(Nlog(N)))
class Solution {
public:
int minIncrementForUnique(vector<int>& A) {
sort(A.begin(), A.end());
int res = 0;
for (int i = 1; i < A.size(); i++) {
if (A[i] <= A[i - 1]) {
res += A[i - 1] - A[i] + 1;
A[i] = A[i - 1] + 1;
}
}
return res;
}
};
重点思路
考虑到最终结果排序后一定是一个严格单调的数列,那么就很容易想到先排序,再构造出一个严格单调的数列。move的次数为上一个数比当前数大的值+1,同时当前值变为比上一个数大1的值。
解答2:计数排序(O(N))
class Solution {
public:
int minIncrementForUnique(vector<int>& A) {
int mv[40000]; bzero(mv, sizeof mv);
int minVal = INT_MAX, maxVal = 0, res = 0;
for (int i : A) {
minVal = min(minVal, i);
maxVal = max(maxVal, i);
mv[i]++;
}
for (int i = minVal; i < maxVal; i++) {
if (mv[i] > 1) {
res += mv[i] - 1;
mv[i + 1] += mv[i] - 1;
}
}
res += mv[maxVal] * (mv[maxVal] - 1) / 2;
return res;
}
};
重点思路
mv中记录A中对应数字出现的次数,数字作为mv的脚标。为了避免第二个for循环遍历整个mv数组,设置最大最小值。在第二个for循环中,当当前数字出现的次数大于1时,只留一个数不变,其余的都+1,堆到下一个数那里去,到最后处理maxVal
处的数,把它们依次排开就好,首项加末项乘项数除以2。