原题:点击此处
考点:排序、线性探测法
本题题解参考:线性探测法的路径压缩
解题:
- 本题的数字数量不会超过40000,最差情况必须考虑到80000。
- 第一时间想到了哈希表,可以用哈希表遍历一遍数组,得到数字与对应的频率,然后通过线性探测的方法,保证所有的数字频率都是“1”。(超时)
- 第二种思路是时间复杂度最为简单的“排序”,利用java内置soft函数。时间复杂度为O(nlogn);
- 第三种思路即线性探测法的路径压缩法。
用数组来记录路径,如果当前位置没有被占据,则放入,并把之前路过的地方全部置为此数字,以便于后面的数字进行遍历的时候,可以跳过已经检查过的地方,时间复杂度为O(n),空间复杂度O(n);
(强烈推荐观看题解参考,非常值得学习的思路)
下面为第三种思路的代码:
(需要注意的是递归的入口和出口!)
class Solution {
public int minIncrementForUnique(int[] A) {
// 特殊条件
if(A.length == 0 || A.length == 1){
return 0;
}
int[] dp = new int[80000];
Arrays.fill(dp,-1);
int ans = 0;
for(int i : A){
int res = LinearFind(dp,i);
ans += (res - i);
}
return ans;
}
public int LinearFind(int[] dp,int i){
// 递归跳出条件,代表此处没有值
if(dp[i] == -1){
dp[i] = i;
return i;
}
// 路径压缩,探索过的路径记录最终的结果
int road = LinearFind(dp,dp[i]+1);
dp[i] = road;
return road;
}
}
因为排序非常简单,就不打出代码了。
下面是我第一次思考用哈希表的方法,时间复杂度真的太高了,超时了。
先总结到数组题,大致有:哈希表,排序,双指针都是非常常用的方法。
class Solution {
public int minIncrementForUnique(int[] A) {
// 特殊条件
if(A.length == 0 || A.length == 1){
return 0;
}
Map<Integer,Integer> map = new HashMap<>();
// 遍历一次数组
for(int i : A){
map.put(i,map.getOrDefault(i,0)+1);
}
int ans = 0;
// 第二次遍历数组
for(int i : A){
int count = map.get(i);
// 如果本身数组只有一个,就不用管他了
if(count == 1){
continue;
}
while(count != 1){
int newnum = i;
// 进行move操作,加到表里面完全不存在这个数字
while( map.containsKey(newnum) ){
newnum++;
ans++;
}
// 原位置-1
map.put(i,map.get(i)-1);
// 新数字置1;
map.put(newnum,1);
count--;
}
}
return ans;
}
}