一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情。
前言
每日一题,轻松解题
每日一题为刷题系列 每日刷一题LeetCode题,并且对题目进行分析,分享思路。
正文
:使数组唯一的最小增量
难度:中等
题目要求:
给你一个整数数组 nums 。每次 move 操作将会选择任意一个满足 0 <= i < nums.length 的下标 i,并将 nums[i] 递增 1。
返回使 nums 中的每个值都变成唯一的所需要的最少操作次数。
举个例子
输入: nums = [1,2,2]
输出: 1
解释: 经过一次 move 操作,数组将变为 [1, 2, 3]。
:解题
方法一 :计数
首先统计出每个数出现的次数,然后从小到大遍历每个数 x:
-
如果 x 出现了两次以上,就将额外出现的数记录下来(例如保存到一个列表中);
-
如果 x 没有出现过,那么在记录下来的数中选取一个 v,将它增加到 x,需要进行的操作次数为 x - v。
我们还可以对该算法进行优化,使得我们不需要将额外出现的数记录下来。还是以 [1, 1, 1, 1, 3, 5] 为例,当我们发现有 3 个重复的 1 时,我们先将操作次数减去 1 + 1 + 1。接下来,当我们发现 2,4 和 6 都没有出现过时,我们依次将操作次数增加 2,4 和 6。这种优化方法在方法二中也被使用。
解题思路:
由于 nums[i] 的范围为 [0, 40000),我们可以用数组统计出每个数出现的次数,然后对于每个重复出现的数,我们暴力地将它递增,直到它增加到一个没有重复出现的数为止。但这样的方法的时间复杂度较大,可以达到 O(N^2),例如数组 nums 中所有元素都是 1 的情况。
因此,我们不能对重复出现的数暴力的进行递增,而是用以下的做法:当我们找到一个没有出现过的数的时候,将之前某个重复出现的数增加成这个没有出现过的数。注意,这里 「之前某个重复出现的数」 是可以任意选择的,它并不会影响最终的答案,因为将 P 增加到 X 并且将 Q 增加到 Y,与将 P 增加到 Y 并且将 Q 增加到 X 都需要进行 (X + Y) - (P + Q) 次操作。
例如当数组 nums 为 [1, 1, 1, 1, 3, 5] 时,我们发现有 3 个重复的 1,且没有出现过 2,4 和 6,因此一共需要进行 (2 + 4 + 6) - (1 + 1 + 1) = 9 次操作。
编辑代码:
class Solution {
public int minIncrementForUnique(int[] nums) {
int[] count = new int[80000];
for (int x : nums) {
count[x]++;
}
int ans = 0, taken = 0;
for (int x = 0; x < 80000; ++x) {
if (count[x] >= 2) {
taken += count[x] - 1;
ans -= x * (count[x] - 1);
} else if (taken > 0 && count[x] == 0) {
taken--;
ans += x;
}
}
return ans;
}
}
总结
无论做什么分析最重要,其中我们分析了题目,分析了解题思路,其实在分析完解题思路后,代码其实就是很简单的事情了,养成习惯,无论做什么之前,都要进行分析,这样有助于你更快更好的完成这件事。