Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目:给定一个含n个整数的数组nums,其中数组中元素都在区间[1, n]内,要求找出在[1, n]范围内但没有在nums中出现的数字,返回结果。
解题思路
如果存在数字不在nums中,则必然存在相同的数字在nums中,一种思路是将数组所有元素放入HashSet,利用set的去重功能保存已有的数字,之后从1遍历到n,每次遍历查看set中是否存在元素,如果不存在则保存此i,代码如下:
public List<Integer> findDisappearedNumbers(int[] nums) {
HashSet<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
}
ArrayList<Integer> list = new ArrayList<>();
for(int i=0;i<nums.length;i++){
if(!set.contains(i+1)){
list.add(i+1);
}
}
return list;
}
时间复杂度和空间复杂度都是。
既然用到了set,那么很容易想到list,我们可以首先将[1, n] 全部放入list,之后遍历数组,如果list中存在该对象,则直接删除,最终保留的list即为最终的结果,代码如下:
public List<Integer> findDisappearedNumbers2(int[] nums) {
ArrayList<Integer> list = new ArrayList<>();
for(int i=0;i<nums.length;i++){
list.add(i+1);
}
for(int i=0;i<nums.length;i++){
if(list.contains(nums[i])){
list.remove((Integer)nums[i]);
}
}
return list;
}
时间复杂度为,因为arrayList.remove的时间复杂度为,空间复杂度为。list不算额外空间。
思路进阶
题目保证了数组中元素的范围为[1, n],则此时可以根据数组元素将对应位置的元素变成负数,之后查看数组中哪些元素还是正数即可得到缺失的元素,代码如下:
public List<Integer> findDisappearedNumbers3(int[] nums) {
ArrayList<Integer> list = new ArrayList<>();
for(int i=0;i<nums.length;i++){
if(nums[Math.abs(nums[i])-1]>0) nums[Math.abs(nums[i])-1] = - nums[Math.abs(nums[i])-1];
}
for(int i=0;i<nums.length;i++){
if(nums[i]>0) list.add(i);
}
return list;
}
循环中的判断很有必要,此处需要注意。最终时间复杂度为,空间复杂度为。