剑指offer题库总结(一)之数组(C语言版本)
题56:数组中只出现一次的两个数字
- 题目具体要求:一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
- 数据范围:数组长度 2≤n≤1000,数组中每个数的大小 0 < val ≤1000
- 要求:空间复杂度 O(1),时间复杂度 O(n)
- 提示:输出时按非降序排列。
示例1
输入:[1,4,1,6]
返回值:[4,6]
说明:返回的结果中较小的数排在前面
- 解题思路:
1.总体思路:有一道和它类似的题,它所指的数组中只有一个出现一次的数,而解法就是从头开始不断地异或下去,由于相同的两个数异或值为0,因此最终的异或结果就是答案
2.而本题有两个只出现一次的数a和b,我们按异或方法最终只能得到a异或b的值,就需要思考一下这两个数异或的结果有何特点
3.我们可以发现,首先这两个数一定不同,故异或结果一定不为0,那么a异或b的结果中一定有一位为1,假设是第x位,那么就说明了a和b的二进制的第x位是不同,根据这一特点,我们可以将数组分为两个集合,即第x位为1的数和第x位为0的数,两部分的异或和即为a和b的值
4.要快速求得最后一位1,可以用lowbit运算(即x&(-x)),它可以快速得到x的最后一位1。
#include <cstdio>
int* FindNumsAppearOnce(int* data, int length, int *ResultArr) {
int Temp = 0;
int idx;
int mask = 1;
int resultA = 0;
int resultB = 0;
for (idx = 0; idx < length; idx++)
{
Temp ^= data[idx];
}
while ((Temp & mask) == 0)
{
mask = mask << 1;
}
for (idx = 0; idx < length; idx++)
{
if ((data[idx] & mask) == 0)
{
resultA ^= data[idx];
}
else
{
resultB ^= data[idx];
}
}
if (resultA > resultB)
{
Temp = resultA;
resultA = resultB;
resultB = Temp;
}
*ResultArr = resultA;
*(ResultArr + 1) = resultB;
return ResultArr;
}
void Test(const char* testName, int data[], int length, int expected1, int expected2)
{
if (testName != nullptr)
printf("%s begins: ", testName);
int result[2];
FindNumsAppearOnce(data, length, &result[0]);
if ((expected1 == result[0] && expected2 == result[1]) ||
(expected2 == result[0] && expected1 == result[1]))
printf("Passed.\n\n");
else
printf("Failed.\n\n");
}
void Test1()
{
int data[] = {
2, 4, 3, 6, 3, 2, 5, 5 };
Test("Test1", data, sizeof(data) / sizeof(int), 4