夯实算法-找到所有数组中消失的数字

159 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的33天,点击查看活动详情

题目:LeetCode

给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。

示例 1:

输入: nums = [4,3,2,7,8,2,3,1]
输出: [5,6]

示例 2:

输入: nums = [1,1]
输出: [2]

提示:

  • n == nums.length
  • 1<=n<=1051 <= n <= 10^5
  • 1 <= nums[i] <= n

解题思路

题目限定了不能使用额外空间,且时间复杂度为O(n),所以HashSet或者数组排序都无法使用 因为数组中存储的元素在[1,n]之间,理想情况下:索引 0n-1 就对应元素 1n,即数组中存储的元素值1~n有且只有1个,但是顺序是打乱的

那么非理想情况下,也就是某些元素存在缺失情况,我们可以利用元素值对应的索引进行标记:

index = nums[i]; //将元素作为索引index

nums[index-1] = (-1) * nums[index-1] //将index对应的元素值标记,代表自己是存在的

但是有些元素可能出现两次或者多次,可能出现负负得正的情况,所以我们要取绝对值.

这道题的思想和计数排序很相似,本质都是借助元素值对应的索引进行操作,只要理解这个思想,代码并不难

代码实现

class Solution {
    public List < Integer > findDisappearedNumbers(int[] nums) {
        List < Integer > res = new ArrayList < > ();
        int n = nums.length;
        //如果nums没有元素,直接返回空list
        if (n == 0) return res;

        for (int i = 0; i < n; i++) {
            int index = Math.abs(nums[i]);
            //标记元素所对应的索引(因为一个数字可能出现多次,所以要取绝对值进行标记)
            nums[index - 1] = -1 * Math.abs(nums[index - 1]);
        }
        //标记完毕后,遍历数组,如果有元素没有被标记到(即元素值>0),就添加到list
        for (int i = 0; i < n; i++) {
            if (nums[i] > 0) {
                res.add(i + 1);
            }
        }
        return res;
    }
}

运行结果

Snipaste_2022-12-31_16-33-35.png

复杂度分析

  • 空间复杂度:O(1)O(1)
  • 时间复杂度:O(n)O(n)

掘金(JUEJIN)  一起分享知识, Keep Learning!