题目:见下图
答案:见下图
int* singleNumber(int* nums, int numsSize, int* returnSize) {
int ret = 0;
for (int i = 0; i < numsSize; i++) {
ret ^= nums[i];
}
// 找第m位数,以区分
int m = 0;
while (m < 32)
{
if (ret & (1 << m))
break;
else
m++;
}
// 分离
int x1 = 0, x2 = 0;
for (int i = 0; i < numsSize; i++) {
if (nums[i] & (1 << m)) {
x1 ^= nums[i];
} else {
x2 ^= nums[i];
}
}
//储存
int* retArr = (int*)malloc(sizeof(int) * 2);
retArr[0] = x1;
retArr[1] = x2;
*returnSize = 2;
return retArr;
}
解析:
在做此题前我们需要先补充一些知识
1.异或是一种二进制的位运算
符号以 ^ 表示,相同为0,不同为1
任何二进制数与零异或,都会等于其本身,即 A ^ 0 = A
2.按位与"&"功能是参与运算的两数各对应的二进位相与,只有对应的两个二进位均为1时,结果位才为1 ,否则为0
3.左移(<<):0011 << 1 = 0110
右移(>>):0110 >> 1 = 0011
(1)将数组nums与0进行异或
当我们得到整形数组nums,我们为了进行分离数,可以将数组与0进行异或,这样出现两次的数就会被消除,仅留下仅出现一次的数ret
int ret = 0;
for (int i = 0; i < numsSize; i++) {
ret ^= nums[i];
}
(2)找出为一的位次m
异或后的数ret以二进制的形式进行储存,二进制共32位,根据异或规则,不同为1,当第m位次两个仅出现一次的数,一个为0一个为1,异或结果为1,那么我们就可以找出任意一位位次为一的位次m,
int m = 0;
while (m < 32)
{
if (ret & (1 << m))
break;
else
m++;
}
(3)将数组根据m位次分组
将数组nums的元素进行分离至x1,x2,此时两个仅出现一次的数,两数m位次不相同一个为0,一个为1,必然会一个分到x1,一个分到x2,将其用&进行判断,分组
并且将储存进入x1,x2的数字与0进行异或,此时x1,x2出现两次的数都被异或掉了,仅留下两个出现一次的数
int x1 = 0, x2 = 0;
for (int i = 0; i < numsSize; i++) {
if (nums[i] & (1 << m)) {
x1 ^= nums[i];
} else {
x2 ^= nums[i];
}
}
(4)开辟数组储存出现一次的数字
这里需要有需要补充malloc函数知识
开辟空间用malloc函数,其头文件是#include <malloc.h>
malloc函数用法 : 指针自身 = (指针类型*)malloc(sizeof(指针类型)*数据数量)
开辟数组我们使用malloc函数,并且将x1与x2分别储存到新开辟的数组retArr中
返回元素个数2,返回开辟的新数组retArr
int* retArr = (int*)malloc(sizeof(int) * 2);
retArr[0] = x1;
retArr[1] = x2;
*returnSize = 2;
return retArr;
到这里我们解题完毕
如果对您有帮助的话点一个免费的赞和收藏叭!