问题:
给定数组,给数组的一些值+1作为一个move,使得该数组成为一个没有重复元素的递增数组,
求最小的move。
Example 1: Input: [1,2,2] Output: 1 Explanation: After 1 move, the array could be [1, 2, 3]. Example 2: Input: [3,2,1,2,1,7] Output: 6 Explanation: After 6 moves, the array could be [3, 4, 1, 2, 5, 7]. It can be shown with 5 or less moves that it is impossible for the array to have all unique values. Note: 0 <= A.length <= 40000 0 <= A[i] < 40000
解法1:
需要两个游标,一个遍历数组元素 i,一个遍历数组中没有的值 j
前提,构成cout数组,记录A每个元素出现的个数。(才能有上面的两个游标遍历)
♻️构建cout数组的同时,记录A的最大值maxA,这样遍历数组元素 i 的时候,只需要遍历到这个最大值即可,
不需要遍历完整个40001个元素。
数组元素 i 的移动条件是:元素 i 不重复。即不需要进行move
一直找到需要move的 i
非数组元素 j 的移动条件是:j 在数组中,cout[j]!=0 或者 当前的 j 小于 i,那么没法+1
一直找到不再数组中的 j:cout[j]==0 且 j 是 i要+1移动到的 j
找到这样的 i 和 j 后,
结果即是 i 和 j 的差值,即为 i 到 j ,move的次数。
同时 i 的个数-1;
代码参考:
1 class Solution { 2 public: 3 int minIncrementForUnique(vector<int>& A) { 4 int cout[40001]={0}; 5 int i=0,j=0; 6 int res=0; 7 int maxA=0; 8 for(int a:A){ 9 cout[a]++; 10 maxA=max(a,maxA); 11 } 12 while(i<=maxA){ 13 while(i<=maxA && cout[i]<=1) i++; 14 while(i>j || j<=maxA && cout[j]!=0) j++; 15 if(i<=maxA){ 16 res+=(j-i); 17 cout[i]--; 18 j++; 19 } 20 } 21 return res; 22 } 23 };
解法2:
递归寻找法:
构建寻找 i 所要move 到的 j的一个数据结构 visited。visited[i]=j
遍历数组A,第一次访问到元素 a 的时候,将 i 加入到 visited,且记录当前的 i 需要move 到的是 a(自己)。
那么它的move=j-i;
第二次访问到 a 的时候,在visited中找到了a,即visited[a]=a ,存在在visited中,
那么需要尝试下一个数字:(从当前记录的上次最新查找对象 j 开始+1 去尝试)j+1=visited[a]+1=a+1
如果这次尝试的对象 j+1 还是存在在visited中,递归继续去尝试visited[j+1]上记录的下一个尝试对象+1
一直找到不存在这样的 尝试结果k。返回。
那么它的move=k-i
代码参考:
1 class Solution { 2 public: 3 unordered_map<int, int> visited; 4 //visited[i]=j: 对于A的元素值i,要变换的下一个值应该为j 5 int minIncrementForUnique(vector<int>& A) { 6 int res=0; 7 for(int a:A){ 8 res+=find(a)-a; 9 } 10 return res; 11 } 12 int find(int a){ 13 if(visited.count(a)!=0) visited[a]=find(visited[a]+1); 14 else visited[a] = a; 15 return visited[a]; 16 } 17 };