题目链接:[Leetcode]448.找到所有数组中消失的数字
题干
给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。
找到所有在 [1, n] 范围之间没有出现在数组中的数字。
特殊要求
您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。
暴力思路
利用O(n)的空间存储结果,然后遍历一遍做标记,便利第二遍获得结果。然而这个思路不符合特殊要求的没有额外空间
正确思路
这道题要做的,是在有限空间中,使得原数组中,存在两种不同的表示方法。假设某索引位最终为表示方法X,则说明出现过,若表示方法为Y,则说明未出现,添加到结果中。
拆分方法1:取模拆分
第一遍遍历时,对于取到的数字number,将nums[number]位数字添加n,则最终某个索引位数字小于n,则说明这个索引位没有出现过。大致代码如下:
// 第一遍遍历做标记
for(auto number : nums){
number = (number - 1) % n;
nums[number] += n;
}
// 第二遍查找结果项
for(int i = 0; i < n; i++){
if(nums[i] < n){
ans.push_back(i + 1);
}
}
拆分方法2:负数区分
这个方法比方法1要巧妙,因为对于n很大的情况,方法1可能存在int溢出问题。
方法2的思路是,标记过程中,将标记内容变为负数,则所有仍为正数的索引位数字即为所求。大致代码:
for(auto number : nums){
nums[abs(number) - 1] = -abs(nums[abs(number) - 1]);
}
for(int i = 0; i < n; i++){
if(nums[i] > 0){
ans.push_back(i + 1);
}
}