leetcode 945使数组唯一的最小增量

给定整数数组 A,每次 move 操作将会选择任意 A[i],并将其递增 1。

返回使 A 中的每个值都是唯一的最少操作次数。

输入:[3,2,1,2,1,7]
输出:6
解释:经过 6 次 move 操作,数组将变为 [3, 4, 1, 2, 5, 7]。
可以看出 5 次或 5 次以下的 move 操作是不能让数组的每个值唯一的。

一定先看清题目,消除重复的方法只有递增。

方法一:
先进行排序,从左到右遍历数组 O(logN)

  • 如果当前的数大于前一个数,保持不变
  • 如果当前的数小于等于前一个数,一直加直到大于前一个数
class Solution {
public:
    int minIncrementForUnique(vector<int>& A) {
        int n = A.size();
        if(n == 0) return 0;
        sort(A.begin(),A.end());
        int res = 0;
        for(int i = 1; i < n; i++){
            if(A[i] <= A[i-1]){//果当前的数小于等于前一个数,一直加直到大于前一个数
                int t = A[i];
                A[i] = A[i-1] + 1; //确保肯定大于前一个数
                res += A[i] - t;
            }
        }
        return res;
    }
};

方法二:
采用计数排序,统计每个元素出现的次数。O(N)

class Solution {
public:
    int minIncrementForUnique(vector<int>& A) {
        int n = A.size();
        if(n == 0) return 0;
        vector<int> counter(40000,0); //记录每个数字出现的次数
        int maxNum = -1; //保存当前数组中的最大值
        for(int i = 0; i < n; i++){
            counter[A[i]]++;
            maxNum = max(maxNum,A[i]); 
        }
        int res = 0;
        // 遍历counter数组,若当前数字的个数cnt大于1个,则只留下1个,其他的cnt-1个后移
        for(int num = 0; num <= maxNum; num++){
            if(counter[num] > 1){
                int t = counter[num] - 1;
                res += t;
                counter[num+1] += t;
            }
        }
        //counter[maxNum+1]里可能会有从counter[max]后移过来的,counter[maxNum+1]里只留下1个,其它的d个后移。
        if(maxNum < 39999){
            int t = counter[maxNum+1] - 1;
            res += (1 + t)*t/2;
        }
        return res;
    }
};

方法三:
解法

class Solution {
    vector<int> pos;
    int findPos(int a){
        int b = pos[a];
        if(b == -1){ //对于的位置时空的,直接放入
            pos[a] = a;
            return a;
        }
        //否则向后寻址
        // 因为pos[a]中标记了上次寻址得到的空位,因此从pos[a]+1开始寻址就行了(不需要从a+1开始)。
        b = findPos(b+1);
        pos[a] = b;
        return b;
    }
public:
    int minIncrementForUnique(vector<int>& A) {
        int n = A.size();
        if(n == 0) return 0;
        int res = 0;
        pos = vector<int>(80000,-1);//-1代表空位。最坏情况下有40000个重复的数
        //遍历每个数字A[i]对其寻地址得到位置b, b比A[i]的增量就是操作数
        for(auto a : A){
            int b = findPos(a);
            res += b - a;
        }

        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值