编号0026 数组中数字出现的次数
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
题目示例如下
这里其实是一道我一个月之前做的题目
在学弟的博客里刚好看到了 又翻了翻自己的博客 好像没有这道题目的题解
刚看到第一眼还以为自己不会了 慢慢梳理了下思路
这里其实又很多种做法 排序之后对比前后数字啊
使用一个很大的数组将它们依次赋值给数组里面对应的值啦
当然这里最优的解法应该是异或法
我们想想看将整个数组里面所有的元素异或 是不是就能得到那两个不同数字的异或了
(因为相同的数字异或都变成0了)
那么首先 我们可以将整个数组异或下来得到一个数字
就像这样
//首先使用一个测试数字0 让他一一和数组里面的异或
//异或完毕之后就会只剩下两个数字的异或结果
int test = 0;
int i = 0;
for(i=0;i<numsSize;i++)
{
test^=nums[i];
}
之后得到这个结果了之后怎么办呢?
我们之后要将整个数组分成两个 尤其是这两个不同的数字要在不同的组别中
那么要怎么分呢?
这也是这个题目唯一的难点
我们可以利用 ‘位’ 来分组
我们都知道了 test是这两个数字异或的结果
那么说明了什么呢?
是不是这个数字的二进制中为1的位 一定是这两个数的位不同的
仔细思考下异或的性质
那么想明白这个事情之后就简单了
我们开始利用这个性质分组
首先找出不同的位在哪里(1)
// 之后我们可以将这个数组分成两个 (这其中两个数字要不在同一个地方)
// 这两个数字异或结果为1的地方一定是不相等的
// 所以我们首先要找出第一个出现1的地方
// 我们使用count来计数这个1出现的地方
int count =0;
for(i=0;i<32;i++)
{
if((test>>i)&1==1)
{
break;
}
count++;
}
再之后分别异或下就可以了
// 之后我们用count将数组分组 分别异或两个数得到的就是两个数了
int num1 = test;
int num2 = test;
for(i=0;i<numsSize;i++)
{
if((nums[i]>>count)&1 == 1)
{
num1^=nums[i];
}
else
{
num2^=nums[i];
}
}
//存放到动态数组里面
int* a = (int*)malloc(sizeof(int)*2);
a[0]=num1;
a[1]=num2;
// 最后设定下返回数组的大小就可以
*returnSize = 2;
return a;
}
整体代码表示如下
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* singleNumbers(int* nums, int numsSize, int* returnSize)
{
//首先使用一个测试数字0 让他一一和数组里面的异或
//异或完毕之后就会只剩下两个数字的异或结果
int test = 0;
int i = 0;
for(i=0;i<numsSize;i++)
{
test^=nums[i];
}
// 之后我们可以将这个数组分成两个 (这其中两个数字要不在同一个地方)
// 这两个数字异或结果为1的地方一定是不相等的
// 所以我们首先要找出第一个出现1的地方
// 我们使用count来计数这个1出现的地方
int count =0;
for(i=0;i<32;i++)
{
if((test>>i)&1==1)
{
break;
}
count++;
}
// 之后我们用count将数组分组 分别异或两个数得到的就是两个数了
int num1 = test;
int num2 = test;
for(i=0;i<numsSize;i++)
{
if((nums[i]>>count)&1 == 1)
{
num1^=nums[i];
}
else
{
num2^=nums[i];
}
}
//存放到动态数组里面
int* a = (int*)malloc(sizeof(int)*2);
a[0]=num1;
a[1]=num2;
// 最后设定下返回数组的大小就可以
*returnSize = 2;
return a;
}
总的来说还是很开心的! 一个月前死活想不出来的题目现在看一眼有思路 十分钟就可以敲出来了
继续加油!