1、题目描述
给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。
找到所有在 [1, n] 范围之间没有出现在数组中的数字。
您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。
示例:
输入: [4,3,2,7,8,2,3,1]
输出: [5,6]
2、解题思路
注意题目要求不能使用额外空间,这也是这道题的难点所在(如果没有不能使用额外空间这个要求的话,直接创建一个数组int hash[26] = {0}; for(int i=0;i<nums.size();i++){hash[nums[i]-1] += 1;}
找hash中为0的就是缺少的)。这道题里面其实包含了隐藏的条件,1<= nums[i] <= n
,即每个数字本身都对应一个0<= i <= n-1
的数组下标。我们可以利用数组内容本身跟数字下标的关联找出缺失的数字。扫描两遍数组,第一次将所有数字做标记,第二次根据标记信息找出缺失的数字。
假设有数组[1,2,3,4,5,6]如下图:
数组上方的是数组的下标,通过这张图可以发现,数组中的每个值都有一个对应的数组下标,比如值为4的对应下标3。即值为i对应下标i-1
如果数组是乱序的呢?
乱序的数组并不影响,比如值为3的对应的是下标2,值为6的对应的是下标5。
我们可以利用下标这个隐藏条件,再假设有下面数组,数组缺少5
因为每个值为i的都对应下标i-1
,我们将值为i对应的下标i-1
中的数组值nums[i-1]
置为负,比如值是3的对应下标2,我们将nums[2]
中的值设置为-abs(nums[2])
(abs代表取绝对值)。
对[1,2,3,4,6,6]这个数组我们做如下操作:
值1对应下标0,将nums[0]
中的值设置成 -abs(nums[0])
,即-1
值2对应下标1,将nums[1]
中的值设置成 -abs(nums[1])
,即-2
值3对应下标2,将nums[2]
中的值设置成-abs(nums[2])
,即-3
值4对应下标3,将nums[3]
中的值设置成-abs(nums[3])
,即-4
值6对应下标5,将nums[5]
中的值设置成-abs(nums[5])
,即-6
值6对应下标5,将nums[5]
中的值设置成-abs(nums[5])
,即-6
再扫描一遍数组nums:
1、找到大于0的值,值是多少不重要,重要的是值的下标i
2、对下标进行操作,i+1
就是我们要找的缺少的数字。
例如:数组nums中大于0的值是6,它的数组下标是4,说明缺少数字5。
可以反向思考:假如存在数字5,那么它对应的下标就是4,根据上面的操作(值5对应下标4,将nums[4]
中的值设置成-abs(nums[4])
,即为负数),那么下标为4的nums[4]的值就不可能大于0,所以不存在数字5。
如果数组是乱序的,也不会影响其结果。
扫描一遍:
对[2,6,6,1,3,4]这个数组我们做如下操作:
值2对应下标1,将nums[1]
中的值设置成 -abs(nums[1])
,即-6
值6对应下标5,将nums[5]
中的值设置成-abs(nums[5])
,即-4
值6对应下标5,将nums[5]
中的值设置成-abs(nums[5])
,即-4
值1对应下标0,将nums[0]
中的值设置成 -abs(nums[0])
,即-2
值3对应下标2,将nums[2]
中的值设置成-abs(nums[2])
,即-6
值4对应下标3,将nums[3]
中的值设置成-abs(nums[3])
,即-1
数组nums中大于0的值是3(验证上面提到的值不同要,重要的是对应的下标),它的数组下标是4,说明缺少数字5。
再看下题目中的列子,数组[4,3,2,7,8,2,3,1]对应下标i值[3,2,1,6,7,1,2,0],将num[3],num[2],num[1],num[6],num[7],num[0]置为负,得到新数组[-4, -3, -2, -7, 8, 2, -3, -1]
扫描一遍8和2大于0,他们分别对应下标4和下标5,所以缺失的数字是5和6。
复杂度分析:
时间复杂度:O(n),扫描两边数组
空间复杂度:O(1),因为我们在原地修改数组,没有使用额外的空间。
3、代码
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
for(int i=0;i<nums.size();i++)
{
nums[abs(nums[i])-1] = -abs(nums[abs(nums[i])-1]);//abs表示取绝对值
}
vector<int> res;
for(int i=0;i<nums.size();i++)
{
if(nums[i]>0)
res.push_back(i+1);
}
return res;
}
};