数组
nums
包含从0到n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?
示例1 ——
输入:[3,0,1]
输出:2
示例2 ——
输入:[9,6,4,2,3,5,7,0,1]
输出:8
题目链接:消失的数字
这个“消失的数字”问题本质可以转化为单身狗问题来解决。
由异或的运算性质 —— 同0异1
思路
那么,我们就异或遍历0到n所有整数,再异或遍历nums
这个数组中每一个元素。
由异或运算符性质可知,相同的数字都被异或掉了,剩下的那个就是只出现一次的数字。
此问题就已经转化为 —— 单身狗问题
一个数组中只有一个数字是出现一次,其他所有数字都出现了两次。编写一个函数找出这个只出现一次的数字。
代码如下 ——
int missingNumber(int* nums, int numsSize){
int x = 0;
int i = 0;
for(i = 0; i<=numsSize; i++)
{
x ^= i;
}
for(i = 0; i<numsSize; i++)
{
x ^= nums[i];
}
return x;
}
一个整型数组
nums
里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例1 ——
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例2 ——
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
题目链接:两个单身狗的故事
由上一题的经验,我们很容易的想到异或的方法
思路
分组 ——
那么如何分组呢?
输入:nums = [1,2,3,4,5,1,2,3,4,6]
输出:[5,6] 或 [6,5]
既然这两个数字不同,那么它们的二进制表示中,一定有一位不同。
用这个例子来说,我们可以以最低位来划分,也可以以第二位来划分 ——
[101] - 5
[110] - 6
分组:
[110 6 2 2 4 4 ]
[101 5 1 1 3 3 ]
或
[110 6 2 2 3 3 ]
[101 5 1 1 4 4 ]
❄️ 先把所有数字都异或在一起,计算出的ret
,即是5^6
的结果
5 - 101
6 - 110 异或(同0异1)得
011
ret
的二进制表示是1的位即是,5和6的不同位,这样就找到了分组的依据。
❄️之前的学习中,我们知道,二进制位的每一位我们都是可以拿到的,只需要配合>>
和&1
即可。我们就可以找到这两个单身狗数字的一个不同的二进制位的位置pos
。
再用这个位置来划分这两个组即可。
完整代码 :
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* singleNumbers(int* nums, int numsSize, int* returnSize){
int* arr = (int*)malloc(sizeof(int)*2);
*returnSize = 2;
//1.把所有数字都异或在一起
int i = 0;
int ret = 0;
for(i = 0; i < numsSize; i++)
{
ret ^= nums[i];
}
//2.找到这两个单身狗数字的,不同的二进制位の位置
int pos = 0;
for(i = 0; i < 32; i++)
{
if(((ret>>i) & 1) == 1)
{
pos = i;
break;
}
}
//3. 分组,边分组边异或
int m = 0;
int n = 0;
for(i = 0; i < numsSize; i++)
{
if(((nums[i]>>pos)& 1) == 1)
{
m ^= nums[i];
}
else
{
n ^= nums[i];
}
}
arr[0] = m;
arr[1] = n;
return arr;
}
这两个单身狗就是这样幸福的生活在一起~
这就是天意让他们在茫茫人海中找到彼此吧!哈哈