集合 S
包含从1到 n
的整数。不幸的是,因为数据错误,导致集合里面某一个元素复制了成了集合里面的另外一个元素的值,导致集合丢失了一个整数并且有一个元素重复。
给定一个数组 nums
代表了集合 S
发生错误后的结果。你的任务是首先寻找到重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。
示例 1:
输入: nums = [1,2,2,4] 输出: [2,3]
注意:
- 给定数组的长度范围是 [2, 10000]。
- 给定的数组是无序的。
拿到这题,正常的思路,拿一个hashmap记录出现的次数,如果多次出现即为重复的数,记录下来。然后用另外一个循环记录缺失的数。执行速度不稳定,最高打败了50%的人
代码如下:
1 class Solution { 2 public int[] findErrorNums(int[] nums) { 3 int[] ans = new int[2]; 4 Map<Integer, Integer> map = new HashMap<>(); 5 for (int i = 0; i < ans.length; i++) { 6 if (!map.containsKey(ans[i])) { 7 map.put(nums[i], 1); 8 } else { 9 ans[0] = nums[i]; 10 } 11 } 12 for (int i = 0; i < nums.length; i++) { 13 if (!map.containsKey(ans[i])) { 14 ans[1] = nums[i]; 15 break; 16 } 17 } 18 return ans; 19 20 } 21 }
考虑到Map的查找效率不是太高,于是改进版使用了一个标记数组来代替Map的功能。道理是一样的。形如 :标记数组[nums的值]=nums的值出现的个数
首先赋值标记数组全部为0,然后遍历nums给标记数组赋值,最后遍历标记数组,如果标记数组在index的值为2,则index这个数重复了两次,如果在index这个位置的值为0,则说明index这个数没有出现过。
这样做的效率变高了许多。
代码如下:
1 class Solution { 2 public int[] findErrorNums(int[] nums) { 3 int[] ans = new int[2]; 4 int[] mark=new int[nums.length+1]; 5 Arrays.fill(mark, 0); 6 for(int i=0;i<nums.length;i++) 7 { 8 mark[nums[i]]++; 9 } 10 for(int i=1;i<mark.length;i++) 11 { 12 if(mark[i]==2) 13 ans[0]=i; 14 if(mark[i]==0) 15 ans[1]=i; 16 } 17 return ans; 18 } 19 }