计数O(N)/线性探测法+路径压缩O(N)/排序O(NlogN), 一眼就明白
一.排序(nlogn)
class Solution {
public :
int minIncrementForUnique ( vector< int > & A) {
int n= A. size ( ) ;
if ( n== 0 ) return 0 ;
sort ( A. begin ( ) , A. end ( ) ) ;
vector< int > dp ( n) ;
for ( int i= 1 ; i< n; i++ ) {
if ( A[ i] <= A[ i- 1 ] ) {
dp[ i] = dp[ i- 1 ] + A[ i- 1 ] - A[ i] + 1 ;
A[ i] = A[ i- 1 ] + 1 ;
}
else dp[ i] = dp[ i- 1 ] ;
}
return dp[ n- 1 ] ;
}
} ;
不用dp数组:
class Solution {
public :
int minIncrementForUnique ( vector< int > & A) {
int n= A. size ( ) ;
if ( n== 0 ) return 0 ;
sort ( A. begin ( ) , A. end ( ) ) ;
int move= 0 ;
/ 遍历数组,若当前元素小于等于它的前一个元素,则将其变为前一个数+ 1
for ( int i= 1 ; i< n; i++ ) {
if ( A[ i] <= A[ i- 1 ] ) {
move+ = A[ i- 1 ] - A[ i] + 1 ;
A[ i] = A[ i- 1 ] + 1 ;
}
}
return move;
}
} ;
二、计数排序O(N)
class Solution {
public :
int minIncrementForUnique ( vector< int > & A) {
if ( A. size ( ) == 0 ) return 0 ;
vector< int > counter ( 40002 ) ;
/ counter数组统计每个数字的个数。
/ (这里为了防止下面遍历counter的时候每次都走到40000 ,所以设置了一个max,这个数据量不设也行,再额外设置min也行)
int Max= INT_MIN;
for ( int num: A) {
counter[ num] ++ ;
Max= max ( Max, num) ;
}
/ 遍历counter数组,若当前数字的个数cnt大于1 个,则只留下1 个,其他的cnt- 1 个后移
int move= 0 ;
for ( int i= 0 ; i<= Max; i++ ) {
if ( counter[ i] > 1 ) {
int d= counter[ i] - 1 ;
move+ = d;
counter[ i+ 1 ] + = d;
}
}
/ 最后, counter[ max+ 1 ] 里可能会有从counter[ max] 后移过来的,counter[ max+ 1 ] 里只留下1 个,其它的d个后移。
/ 设 max+ 1 = x,那么后面的d个数就是[ x+ 1 , x+ 2 , x+ 3 , . . . , x+ d] ,
/ 因此操作次数是[ 1 , 2 , 3 , . . . , d] , 用求和公式求和
int d= counter[ Max+ 1 ] - 1 ;
move+ = ( 1 + d) * d/ 2 ;
return move;
}
} ;
三、线性探测法O(N) (含路径压缩)
class Solution {
public :
/ 线性探测寻址(含路径压缩)
int findPos ( int a, vector< int > & pos) {
int b= pos[ a] ;
/ 如果a对应的位置pos[ a] 是空位,直接放入即可。
if ( b== - 1 ) {
pos[ a] = a;
return a;
}
/ 否则向后寻址
/ 因为pos[ a] 中标记了上次寻址得到的空位,因此从pos[ a] + 1 开始寻址就行了(不需要从a+ 1 开始)。
b= findPos ( b+ 1 , pos) ;
/ 寻址后的新空位要重新赋值给pos[ a] 哦,路径压缩就是体现在这里。
pos[ a] = b;
return b;
}
int minIncrementForUnique ( vector< int > & A) {
/ 最坏情况是40000 个40000
vector< int > pos ( 80000 , - 1 ) ;
int move= 0 ;
/ 遍历每个数字a对其寻地址得到位置b, b比a的增量就是操作数。
for ( int a: A) {
int b= findPos ( a, pos) ;
move+ = b- a;
}
return move;
}
} ;