题目
给定整数数组 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
思路
采用贪心策略(重复元素后的最佳 move 位置,例如 [ 1, 1, 3 ] 中,对重复元素 1 的最佳 move 位置为 2 而不是 4)对数组元素所占范围的空隙进行“占领”。首先,对数组进行排序;其次,将重复元素入栈(其实也可以不用栈);最后,将栈中元素放入到数组元素范围内的空隙中,并记录所需move操作数。实现如下:
class Solution {
public:
int minIncrementForUnique(vector<int>& A) {
if(A.empty())
return 0;
fastsort(A, 0, A.size()-1);
stack<int> s;
int ans=0;
for(int i=0; i<A.size()-1; i++){
if(A[i] == A[i+1])
s.push(A[i+1]);
else if(A[i+1]-A[i] > 1){
for(int j=A[i]+1; j<A[i+1]; j++){
if(!s.empty()){
int v=s.top();
s.pop();
ans+=j-v;
}else
break;
}
}
}
int p=A[A.size()-1]+1;
while(!s.empty()){//“空隙”放不下,放到最后。
int v=s.top();
s.pop();
ans+=p-v;
p++;
}
return ans;
}
void fastsort(vector<int>& A, int lo, int hi){
if(lo>=hi)
return;
int p=partition(A, lo, hi);
fastsort(A, lo, p-1);
fastsort(A, p+1, hi);
}
int partition(vector<int>& A, int lo, int hi){
int v=A[lo];
int i=lo, j=hi+1;
while(true){
while(A[++i]<v) if(i==hi) break;
while(v<A[--j]) if(j==lo) break;
if(i>=j) break;
swap(A[i], A[j]);
}
swap(A[lo], A[j]);
return j;
}
};