题目描述:
给定整数数组 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 操作是不能让数组的每个值唯一的。
解题思路1:
当我们找到一个没有出现过的数的时候,将之前某个重复出现的数增加成这个没有出现过的数。注意,这里 「之前某个重复出现的数」 是可以任意选择的,它并不会影响最终的答案,因为将 P 增加到 X 并且将 Q 增加到 Y,与将 P 增加到 Y 并且将 Q 增加到 X 都需要进行 (X + Y) - (P + Q) 次操作。
例如当数组 A 为 [1, 1, 1, 1, 3, 5] 时,我们发现有 3 个重复的 1,且没有出现过 2,4 和 6,因此一共需要进行 (2 + 4 + 6) - (1 + 1 + 1) = 9 次操作。
代码1:
class Solution:
def minIncrementForUnique(self, A: List[int]) -> int:
count = [0] * 80000
for x in A:
count[x] += 1
ans = taken = 0
for x in range(80000):
if count[x] >= 2:
taken += count[x] - 1
ans -= x * (count[x] - 1)
elif taken > 0 and count[x] == 0:
taken -= 1
ans += x
return ans
解题思路2:
我们可以将数组先进行排序,再使用方法一中提及的优化方法。
代码2:
class Solution:
def minIncrementForUnique(self, A: List[int]) -> int:
A.sort()
A.append(100000)
ans = taken = 0
for i in range(1, len(A)):
if A[i-1] == A[i]:
taken += 1
ans -= A[i]
else:
give = min(taken, A[i] - A[i-1] - 1)
ans += give * (give + 1) // 2 + give * A[i-1]
taken -= give
return ans
解题思路3: (超出了时间限制)
将重复的元素以及次数分别提取到列表C和D中,逐渐加1并判断元素是否在列表中。
代码3:
import numpy as np
from collections import Counter
class Solution(object):
def minIncrementForUnique(self, A):
if len(A) <= 1: return 0
number = 0
B = list(np.unique(A))
if len(B) == len(A): return 0
C = []
D = []
for i in (Counter(A)-Counter(B)).keys():
C.append(i)
for j in (Counter(A)-Counter(B)).values():
D.append(j)
i = 0
temp = C[i]
while len(B) < len(A):
if temp in B:
temp = temp+1
number += 1
else:
D[i] -= 1
B.append(temp)
if 0 == D[i]:
i = i+1
if i >= len(C):
break
else:
temp = C[i]
return number
s = Solution()
A = [2, 2, 2, 1]
print(s.minIncrementForUnique(A))
题目来源:
LeetCode