1.题目描述
The set S originally contains numbers from 1 to n. But unfortunately, due to the data error, one of the numbers in the set got duplicated to another number in the set, which results in repetition of one number and loss of another number.
Given an array nums representing the data status of this set after the error. Your task is to firstly find the number occurs twice and then find the number that is missing. Return them in the form of an array.
Example 1:
Input: nums = [1,2,2,4]
Output: [2,3]
Note:
The given array size will in the range [2, 10000].
The given array’s numbers won’t have any order.
用中文来描述这个题:
给一个长度为 N 的数组 nums,数组原本装有 [1…N] 这 N 个元素,并且元素无序。现在出现了一些错误,nums 中的一个元素出现了重复,也就同时导致了另一个元素的缺失。请你写一个算法,找到 nums 中的重复元素和缺失元素的值。
2.解法1
最简单粗暴的解法自然是用个hashmap各元素出现的次数。
public static void findElement() {
int[] nums = {1, 2, 2, 4};
Map<Integer, Integer> map = new HashMap<>();
for(int i=0; i<nums.length; i++) {
map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
}
for(int i=1; i<=nums.length; i++) {
if (!map.containsKey(i)) {
System.out.println("missing num is: " + i);
} else {
if (map.get(i) == 1) continue;
else {
System.out.println("dup num is: " + i);
}
}
}
}
该种解法是最直接的计数方法,没啥好说的,只要有java基础的都会。
3.解法2
上面的方法需要开辟一个新的hashmap空间。那么能不能省下这个hashmap的空间呢?
如果遍历每个数字,将其应该出现的位置上的数字变为其相反数。
1.这样如果我们再变为其相反数之前已经成负数了,说明该数字是重复数。
2.如果我们再遍历原来的数组,如果发现某个位置上的数字大于0,说明该位置对应的数字没有出现过。
public static void findElement() {
int[] nums = {1, 2, 2, 4};
int dup = -1, missing = -1;
int n = nums.length;
for(int i=0; i<n; i++) {
int index = Math.abs(nums[i]) - 1;
if (nums[index] < 0) {
dup = nums[i];
} else {
nums[index] *= -1;
}
}
for(int j=0; j<n; j++) {
if (nums[j] > 0) {
missing = j + 1;
}
}
System.out.println("dup is: " + dup);
System.out.println("missing is: " + missing);
}