开启掘金成长之旅!这是我参与「掘金日新计划 · 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.length1 <= 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;
}
}
运行结果
复杂度分析
- 空间复杂度:
- 时间复杂度:
在掘金(JUEJIN) 一起分享知识, Keep Learning!