LeetCode No.945 使数组唯一的最小增量

306 阅读2分钟

原题链接

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

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

示例 1:

输入:[1,2,2]
输出:1
解释:经过一次 move 操作,数组将变为 [1, 2, 3]。

提示:

  1. 0 <= A.length <= 40000
  2. 0 <= A[i] < 40000

计数

对原数组一次便利,用新数组来记录每个值出现的次数。循环这个新的数组,对每一个元素进行:

  1. 如果当前元素的数量等于一个,不处理
  2. 如果当前元素数量超过了1个,那么需要将多余的数字给剔除掉。记录下剔除的数量 token 和剔除的总和
  3. 如果当前元素的数量为0,且在此之前已经有过剔除,那么这个数字就是我们需要新增的数字。即 taken-1,ans+=这个数字

这个ans就是我们最终需要增加的数总和。

public int minIncrementForUnique(int[] A) {
        // 因为题目明确了A的最大值为40000,那么在最极限的情况下给的测试用例为40000个40000,那么最终结果数组需要有40000~80000,所以数组数量设定为80000
				int[] arr  = new int[80000];
        for(int i=0;i<A.length;i++){
            arr[A[i]]++;
        }
        
        int taken=0,res=0;
        for(int i=0;i<arr.length;i++){
            if(arr[i] > 1){
                taken += arr[i] - 1;
                res -= i * (arr[i] - 1);
            }else if(taken > 0 && arr[i] == 0){
                taken--;
                res += i;
            }
        }
        return res;
	}
  • 时间复杂度:O(L) 其中 LL 的数量级是数组 A 的长度加上其数据范围内的最大值,因为在最坏情况下,数组 A 中的所有数都是数据范围内的最大值
  • 空间复杂度:O(L) 需要长度 LL 的数组统计每个数出现的次数

排序

对数组进行一次排序后,对每一个元素,保持这个元素比上一个元素至少大于1即可。

		public int minIncrementForUnique(int[] A) {
        Arrays.sort(A);
        int res = 0;
        for(int i=1;i<A.length;i++){
            if(A[i] <= A[i-1]) {
                res += A[i-1] - A[i] + 1;
                A[i] = A[i-1] + 1;
            }
        }
        return res;
    }
  • 时间复杂度:O(nlogn) 排序+一次遍历
  • 空间复杂度:O(logn) 排序需要logn级的栈空间