题目描述:
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]
要完成的函数:
vector<int> findDisappearedNumbers(vector<int>& nums)
说明:
1、给定一个长度为n的vector,里面包含了一些在[1,n]之间的数字,有些数字出现了两次,有些出现了一次,要求输出最后没有出现的数字。
时间复杂度O(n),空间复杂度要求不得使用额外空间,最后要返回的vector不算额外空间。
2、第一时间想到的是异或处理。我们可以把从1到n的数依次与vector异或,得到出现了两次的数的异或结果,比如样例中就是2^3的异或结果。
我们也可以vector里面数字逐个异或,最终得到的是只出现一次的数字的异或结果,比如样例中就是4^7^8^1。
最后我们把从1到n的数字再与上面两个异或结果再异或一次,也就是(1^2^3^4^5^6^7^8)^(2^3)^(4^7^8^1)=5^6,但我们还是不能输出5和6这两个单独的数。
异或只能输出一个数,也就是说只准许,有一个数没有出现两次,其他数都必须出现两次。这种题才能使用异或。
3、那不能用异或,我们考虑一下传统的解法。
时间复杂度为O(n),意味着只能做单重循环。不能使用额外空间,也就是说我们只能在原vector上操作。
那这样子这道题目就有方向了,我们可以在原vector上做循环,看到某个数就把数值对应的vector位置的的值改变一下,最好变得比较明显,比如变成负数什么的。
然后再做一次循环,看看没有还是正数的数值,它们的位置是多少,正数的数值的位置表示没有哪一个数对应了它,也就是在原本vector中没有出现。
举个例子:
[4,3,2,7,8,2,3,1]
第一个数是4,于是把4对应的位置(应该要减1),7这个数置为-7。vector变成[4,3,2,-7,8,2,3,1]
第二个数是3,于是把3对应的位置(应该要减1),2这个数置为-2。vector变成[4,3,-2,-7,8,2,3,1]
第三个数是2,于是把2对应的位置(应该要减1),3这个数置为-3。vector变成[4,-3,-2,-7,8,2,3,1]
第四个数是7(取绝对值),于是把7对应的位置(应该要减1),3这个数置为-3。vector变成[4,-3,-2,-7,8,2,-3,1]
第五个数是8,于是把8对应的位置(应该要减1),1这个数置为-1。vector变成[4,-3,-2,-7,8,2,-3,-1]
第六个数是2,于是把2对应的位置(应该要减1),-3这个数置为-3(负数保持不变)。vector变成[4,-3,-2,-7,8,2,-3,-1]
第七个数是3(取绝对值),于是把3对应的位置(应该要减1),-2这个数置为-2(负数保持不变)。vector变成[4,-3,-2,-7,8,2,-3,-1]
第八个数是1(去绝对值),于是把1对应的位置(应该要减1),4这个数置为-4。vector变成[-4,-3,-2,-7,8,2,-3,-1]
然后再做一次循环,发现第5和第6个数是正数,说明5和6这两个数字没有在原本vector中出现,所以输出就好了。
代码如下:
vector<int> findDisappearedNumbers(vector<int>& nums)
{
vector<int>res;
int t;
for(int i=0;i<nums.size();i++)
{
t=abs(nums[i])-1;
if(nums[t]>0)
nums[t]=-nums[t];
}
for(int i=0;i<nums.size();i++)
{
if(nums[i]>0)
res.push_back(i+1);
}
return res;
}
上述代码实测129ms,beats 88.27% of cpp submissions。