题目链接:https://leetcode.cn/problems/find-all-numbers-disappeared-in-an-array/
思路一:引入Hashmap,遍历数组,将元素存入Hashmap,接下来遍历[1,n],找出不存在于Hashmap的元素,追加到结果数组中。代码如下:
class Solution {
public List<Integer> findDisappearedNumbers(int[] nums) {
if(nums == null) return null;
//遍历nums将元素添加到Hashmap
HashMap<Integer,Integer> curNums = new HashMap<Integer,Integer>();
for(int num:nums) {
if(curNums.get(num) == null) {
curNums.put(num,1);
}
}
List<Integer> result = new ArrayList<Integer>();
//检索HashMap找到不存在的数字
for(int i=1;i<=nums.length;i++) {
if(curNums.get(i) == null) {
result.add(i);
}
}
return result;
}
}
时间复杂度分析:两个非嵌套循环,时间复杂度为O(n)。
空间复杂度分析:创建了一个HashMap存储中间结果,一个result结果数组(不算在额外空间复杂度中),总的空间复杂度为O(n)。
思路二:不引入额外存储空间。思考大小为n的数组,且每个元素值x的区间为[1,n],那么x-1的区间就是[0,n-1],这不是巧合,刚好是这个数组下标的区间。遍历整个数组,将x取出来作为下标找到对应的元素+n,相当于标识出这个下标已经有数字。遍历完之后,只需取出那些元素<=n的下标即为“消失”的数。这里注意,因为可能出现数字重复,因此某一个下标对应的值可能会被加多次,造成索引越界,因此在+n之前需要让x-1对n取余数,代码如下:
class Solution {
public List<Integer> findDisappearedNumbers(int[] nums) {
if(nums == null) return null;
int n = nums.length;
//对于每个数字num,找到num-1位置,将其+n
for(int num:nums) {
nums[(num-1)%n] += n;
}
List<Integer> result = new ArrayList<Integer>();
//找出那些未修改的元素即为没出现过的元素
for(int i=0;i<n;i++) {
if(nums[i]<=n) {
result.add(i+1);
}
}
return result;
}
}
时间复杂度分析:两个非嵌套循环,时间复杂度为O(n)。
空间复杂度分析:没有引入额外的数组,总的空间复杂度为O(1)。