LeetCode 448.找到所有数组中消失的数字

139 阅读1分钟

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;
}

时间复杂度和空间复杂度都是O(n)O(n)

既然用到了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;
}

时间复杂度为O(N2)O(N^2),因为arrayList.remove的时间复杂度为O(n)O(n),空间复杂度为O(1)O(1)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;
}

循环中的判断很有必要,此处需要注意。最终时间复杂度为O(n)O(n),空间复杂度为O(1)O(1)