每日一题:448. 找到所有数组中消失的数字

140 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情

一、题目描述:

448. 找到所有数组中消失的数字 - 力扣(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 <= 10^5
  • 1 <= nums[i] <= n

进阶:你能在不使用额外空间且时间复杂度为 O(n) 的情况下解决这个问题吗? 你可以假定返回的数组不算在额外空间内。

二、思路分析:

当不考虑空间的情况下,可以使用数组来记录每一个位置是否存在数字,这需要一个额外的数组空间。 原地置换的思想是:遍历数组,利用遍历的每一位数字减去一作为下标,然后将此下标的数字进行改变,由于nums[i]在区间[1,n]内,所以将数字加上n。为什么要加上n呢?因为这个被改变的数字有可能是后面的数字,然后减去一,这个数字的下标肯定越界,所以需要模n,这样的话得到的结果跟原来的数字获取的下标是一致的 例如:[4,3,2,7,8,2,3,1],4改变了下标为3的数字变成了nums[3] + 8 = 15;那么遍历到15时,(15-1)%8=6 和 (7-1)%8=6是一致的,不会影响结果,所以才要加上n,当然只要是n的倍数都可以。模n是必不可少的,因为被改变了的数一定大于n。

三、AC 代码:

class Solution {
    public List<Integer> findDisappearedNumbers(int[] nums) {

        int n = nums.length;
        for (int num : nums) {
            int x = (num - 1) % n;
            nums[x] += n;
        }
        List<Integer> ret = new ArrayList<Integer>();
        for (int i = 0; i < n; i++) {
            if (nums[i] <= n) {
                ret.add(i + 1);
            }
        }
        return ret;
    }
}

范文参考:

in rust we trust -- vector (find_disappeared_numbers/448. 找到所有数组中消失的数字) - 找到所有数组中消失的数字 - 力扣(LeetCode)