945.使数组唯一的最小增量(Java)

题目描述

给定整数数组 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


解法一:哈希法(超时)
class Solution {
    public int minIncrementForUnique(int[] A) {
        int n=A.length;
        int count=0;
        Map<Integer,Integer> map=new HashMap<>();
        for(int i:A){
            map.put(i,map.getOrDefault(i,0)+1);
        }
        for(int i:A){
            while(map.containsKey(i)&&map.get(i)>1){
                map.put(i,map.get(i)-1);
                i++;
                if(map.containsKey(i)){
                    map.put(i,map.get(i)+1);
                }
                else{
                    map.put(i,1);
                }
                count++;
            }
            map.put(i,1);
        }
        return count;
    }
}
解法二:数组计数

逐个计算

class Solution {
    public int minIncrementForUnique(int[] A) {
        int n=A.length;
        int count=0;
        int[] arr=new int[80002];
        for(int i:A){
            while(arr[i]==1){
                i++;
                count++;
            }
            arr[i]=1;
        }
        return count;
    }
}

在这里插入图片描述
按序计算

  • 全部存入数组,找出最大最小值,逐个扫描
  • 个数超过1个的,留下一个,其他的都移动到下一位。
  • 最后计算超过max的数列和
class Solution {
    public int minIncrementForUnique(int[] A) {
        int count=0;
        int[] arr=new int[40001];
        int max=-1,min=40001;
        for(int i:A){
            arr[i]++;
            max=Math.max(max,i);
            min=Math.min(min,i);
        }
        for(int i=min;i<=max;i++){
            if(arr[i]>1){
            int d=arr[i]-1;
            count+=d;
            arr[i+1]+=d;
            }
        }
        int d=arr[max+1]-1;
        count+=d*(d+1)/2;
        return count;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z9Tz4iLT-1584888028650)(D:\leetcode\图片\945.使数组唯一的最小增量\0.2.PNG)]

解法三:排序
  • 排序后,若当前值小于等于前一索引值,则
    • count为两者之差+1
    • 当前值为前一值+1;
class Solution {
    public int minIncrementForUnique(int[] A) {
        int count=0;
        Arrays.sort(A);
        for(int i=1;i<A.length;i++){
            if(A[i]<=A[i-1]){
                count+=A[i-1]-A[i]+1;
                A[i]=A[i-1]+1;
            }
        }
        return count;
    }
}

在这里插入图片描述

解法四:线性探测
  • 先将探测数组用-1填充。
  • 往前扫描,找到空位,依次填充。
  • 下一次若探测已经出现过的,会跳过重复路径,直接到达空位前一个位置,再探测一次就能找到空位

案例[3, 2, 1, 2, 1, 7]

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution {
    public int minIncrementForUnique(int[] A) {
        int count=0;
        int[] arr=new int[80000];
        Arrays.fill(arr,-1);
        for(int a:A){
            int b=findPos(arr,a);
            //终点-起点
            count+=b-a;
        }
        return count;
    }
    public int findPos(int[] arr,int a){
        //查看该位置存储的位置。
        int b=arr[a];
        //若未存过,则存储该位置
        if(b==-1){
            arr[a]=a;
            return a; 
        }
        //向前探测,并且把最终的终点位置往回传
        b=findPos(arr,b+1);
        //依次存储终点位置,若不加上则超时
        arr[a]=b;
        return b;
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值