题目:一个整型数组 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]
思路:本题主要使用分组异或的方法解决。
步骤1:对nums数组中的所有元素进行异或,根据异或特点,最终可得到两个只出现一次数字的异或结果。
步骤2:寻找第一次异或后结果中为1的位。
步骤3:根据步骤2中得到的为1的位置,对数组数据进行分组。
步骤4:分组分别再进行一次异或,得到结果。
以示例1为例:
十进制 | 二进制 |
4 | 1000 |
1 | 0001 |
4 | 1000 |
6 | 1010 |
步骤1:将数组[4,1,4,6]依次异或,得到结果为1011。
步骤2:按从低位到高位的次序查找步骤1获取到的结果1011中首次遇到1的位置为最低位。
步骤3:将数组[4,1,4,6]的二进制形式,按最低位是否为0进行分组。
第一组 | 第二组 |
1000 | 0001 |
1000 | |
1010 |
步骤4:按组分别异或,第一组可得到结果为1010即十进制6,第二组为1。
代码实现(C语言):
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* singleNumbers(int* nums, int numsSize, int* returnSize){
int x = 0;
int y = 0;
int ret = 0;
for(int i = 0;i < numsSize; i++)//步骤1
{
ret ^= nums[i];
}
int j = 0;
for(; j < 32; j++)/步骤2
{
if(ret & (1 << j))
break;
}
for(int k = 0; k < numsSize; k++)//步骤3、步骤4:通过条件判断语句分组,同时异或
{
if(nums[k] & (1 << j))
{
x ^= nums[k];
}
else
{
y ^= nums[k];
}
}
//将得到的结果存入数组并返回结果
int* arr = (int*)malloc(sizeof(int) * 2);
arr[0] = x;
arr[1] = y;
*returnSize = 2;
return arr;
}