Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once.
Find all the elements of [1, n] inclusive that do not appear in this array.
Could you do it without extra space and in O(n) runtime? You may assume the returned list does not count as extra space.
example:
Input: [4,3,2,7,8,2,3,1] Output: [5,6]题意:
给你一个数组,数组大小为n,数组里的整数大小都在1和n之间,有些数字出现了两次,其他的则出现一次,找到1到n之间没有出现过的数字。
题目的关键信息有整数大小在1和n之间,且数组大小为n!并且不能使用额外的空间。
因为不能使用额外的空间,所以需要在原来数组的基础上进行处理。假如给数组[4,3,2,7,8,2,3,1],没有出现过的数为5,6。所以在原本数组上进行操作,数组中含有两部分数字信息,一部分为value值,就是nums[index]值,另一部分就是index。通过这两部分信息就可解决该题。
从第一个数开始,nums[0]为4,如果将nums[0]-1看作数组下标,就是数组地四个数,为7,如果为正数,就该数变为负数,如果为负数则还是负数(因为变为负数,经过取绝对值还能得到原始址),所以将7变为-7。接着进行下一个数遍历,nums[1]为3,第三个数为2,则降2变为-2。接着遍历第三个数,为-2,将取绝对值为2,第二个数为3,将3变为-3。依次遍历,直到最后一个数。遍历完以后,就会发现数组中有的是正数,有的是负数,为负数的索引+1所得到的数字,肯定是在数组中出现过,如果一个数没有出现过,则不会处理该数减去1的下标数。所以最后遍历一遍数组,将所有为正数的下标+1就为没有出现的数字。建议大家在纸上把数字改变过程画一画,就一目了然了~
看代码更加直接:
vector<int> findDisappearedNumbers(vector<int>& nums) {
vector<int > list;//存放结果的数组
for(int i=0; i<nums.size(); i++){
int m = abs(nums[i]) - 1;//取数组数的绝对值-1,作为索引值
if(nums[m]>0)//如果索引值为正数,则变为负数,变为负数代表该数被访问过,负数的索引值+1在数组中出现过
nums[m] = -nums[m];
}
for(int i=0; i<nums.size(); i++){
//正数的索引值+1就为没有出现过的数字
if(nums[i]>0)
list.push_back(i+1);
}
return list;
}
如果该题已经理解明白,可以去尝试一下leetCoded的第442题 Find All Duplicates in an Array。与此题非常类似,也很有意思~