题目:
集合 S 包含从1到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个元素复制了成了集合里面的另外一个元素的值,导致集合丢失了一个整数并且有一个元素重复。
给定一个数组 nums 代表了集合 S 发生错误后的结果。你的任务是首先寻找到重复出现的整数,再找到丢失的整数,将它们以数组的形式返回
方法一:暴力解法
最直接的做法就是单独检查 1到 n的所有数字。在检查每个数字时都遍历整个 nums 数组,检查当前数字在 nums中是否出现了两次,或者一次都没有出现。使用 dup 和 missing 记录重复数字和缺失数字。
public class Solution {
public int[] findErrorNums(int[] nums) {
int dup = -1, missing = -1;
for (int i = 1; i <= nums.length; i++) {
int count = 0;
for (int j = 0; j < nums.length; j++) {
if (nums[j] == i)
count++;
}
if (count == 2)
dup = i;
else if (count == 0)
missing = i;
}
return new int[] {dup, missing};
}
}
时间复杂度:O(n^2),在 1到 n 的每个数字上,都需要遍历一次 nums。
空间复杂度:O(1),使用恒定的额外空间。
方法二:使用排序
public class Solution {
public int[] findErrorNums(int[] nums) {
Arrays.sort(nums);
int dup = -1, missing = 1;
for (int i = 1; i < nums.length; i++) {
if (nums[i] == nums[i - 1])
dup = nums[i];
else if (nums[i] > nums[i - 1] + 1)
missing = nums[i - 1] + 1;
}
return new int[] {dup, nums[nums.length - 1] != nums.length ? nums.length : missing};
}
}
时间复杂度:O(nlog n),排序需要 O(nlog n) 的时间。
空间复杂度:O(log n),排序需要 O(log n) 的空间。
方法三:主要思想是通过交换数组元素使数组上的元素在正确的位置
for (int i = 0; i < nums.length; i++) {
while (nums[i] != i + 1 && nums[nums[i] - 1] != nums[i]) {
swap(nums, i, nums[i] - 1);********
}
}
for (int i = 0; i < nums.length; i++) {
if (nums[i] != i + 1) {
return new int[]{nums[i], i + 1};
}
}
return null;
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
方法四:使用Map
public class Solution {
public int[] findErrorNums(int[] nums) {
Map < Integer, Integer > map = new HashMap();
int dup = -1, missing = 1;
for (int n: nums) {
map.put(n, map.getOrDefault(n, 0) + 1);
}
for (int i = 1; i <= nums.length; i++) {
if (map.containsKey(i)) {
if (map.get(i) == 2)
dup = i;
} else
missing = i;
}
return new int[]{dup, missing};
}
}
时间复杂度:O(n) 遍历 nums需要时间 O(n)O(n),在 map 中检查每个数字需要时间 O(n)
空间复杂度:O(n),map 最多需要存储 1 到 n 共 n 个数字
方法五:因为均为正数,可以使用正负反转的思路,遍历数组(数值从1~n),对每一个对应值使得nums[n-1]反转正负,对于出现两次的,在第二次扫描只记录,不反转,未变负数的值即为缺失值,
public class Solution {
public int[] findErrorNums(int[] nums) {
int dup = -1, missing = 1;
for (int n: nums) {
if (nums[Math.abs(n) - 1] < 0)
dup = Math.abs(n);
else
nums[Math.abs(n) - 1] *= -1;
}
for (int i = 1; i < nums.length; i++) {
if (nums[i] > 0)
missing = i + 1;
}
return new int[]{dup, missing};
}
}
时间复杂度:O(n) 两次遍历
空间复杂度:O(n) 恒定空间