持续创作,加速成长!这是我参与「掘金日新计划 · 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;
}
}