单身狗2
题目内容:
在一个数组中,室友两个数字出现了一次,其他所有数字都出现了两次。找出只出现一次的数字。
如:1,2,3,4,5,1,2,3,4,6 5 和6都只出现了一次,找出5和6打印出来
解题思路:
这里还是要用到异或运算符 ^来解决。不过和单身狗1不一样的是,整个数组异或下来,会出现一个别的值,是由5^6得到的。这里我们找新得到的值的二进制位的1在哪里。
注意,异或运算符是两个数的二进制位对应位相同结果为1,不同为0 ,可以用这点来将两个不同的数字分成两个不同的组,然后在分别异或每个组。
1、找出整体异或的结果
int tmp = 0;
int i = 0;
//将整个数组异或起来,得到两个不同数字的异或结果
for (i = 0; i < n; i++)
{
tmp ^= arr1[i];
}
2、找到tmp中,二进制为1 的某一位k
tmp 可能是 0001 0010 0100,所以我们要用到右移运算符 >>
int k = 0;
for (i = 0; i < 32; i++)
{
if (((tmp >> i) & 1) != 0)
{
k = i;
break;
}
}
3、将k位上为1的分为一组遍历异或,最后的值存储到p1或p2中
* p1 = 0;
* p2 = 0;
for (i = 0; i < n; i++)
{
if (((arr1[i] >> k) & 1) != 0)
{
*p1 ^= arr1[i];
}
else
{
*p2 = arr1[i];
}
}
最后来看看完整代码吧
#include <stdio.h>
void Fund(int arr1[], int n, int* p1, int* p2)
{
int tmp = 0;
int i = 0;
//将整个数组异或起来,得到两个不同数字的异或结果
for (i = 0; i < n; i++)
{
tmp ^= arr1[i];
}
//2、找到tmp中,二进制为1 的某一位k
int k = 0;
for (i = 0; i < 32; i++)
{
if (((tmp >> i) & 1) != 0)
{
k = i;
break;
}
}
//3、将k位上为1的分为一组遍历异或,最后的值存储到p1或p2中
* p1 = 0;
* p2 = 0;
for (i = 0; i < n; i++)
{
if (((arr1[i] >> k) & 1) != 0)
{
*p1 ^= arr1[i];
}
else
{
*p2 = arr1[i];
}
}
}
int main()
{
int arr[] = { 1,2,3,4,5,1,2,3,4,6 };
int sz = sizeof(arr) / sizeof(arr[0]);
int num1 = 0;
int num2 = 0;
Fund(arr, sz, &num1, &num2);
printf("%d %d\n", num1, num2);
return 0;
}
结果:
消失的数字
题目链接:. - 力扣(LeetCode)
这道题不是很难,但有一个限制,就是在时间复杂度上是O(N)
方法一:计算总和
这个算是最简单也是最常规的解法了。
int missingNumber(int* nums, int numsSize)
{
int i=0;
int sum=0;
//先遍历计算出0-n的总和
for(i=1;i<=numsSize;i++)
{
sum+=i;
}
//再用计算出的和减去数组的每一项
for(i=0;i<numsSize;i++)
{
sum-=nums[i];
}
return sum;
}
方法二:异或
这个方法与单身狗类似。就是a^a=0,a^0=a。
先让1~N的数异或一遍。结果在与数组异或一遍。
int missingNumber(int* nums, int numsSize)
{
int i=0;
int sum=0;
for(i=1;i<=numsSize;i++)
{
sum^=i;
}
for(i=0;i<numsSize;i++)
{
sum^=nums[i];
}
return sum;
}