一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
//第一次尝试:
//在本题中,由于限制了时间复杂度为O(n),就不能使用双重循环做排序,然后遍历找单身数字;空间复杂度为O(1),就不能再申请n个空间来对出现的数字进行计数,然后找出单身数字;
//所以,本题只能使用异或的妙用(异或很重要哦,用法都很巧妙):
//首先假设如果只有一个数字只出现了一次,那么我们就可以将nums中的所有数字进行异或,得到的结果就是单身数字;
//所以,依照上面的思路,只要将单身数字a、b分到不同的组s1、s2,并且s1、s2中的其他数字也是成对出现的,那么再对s1、s2进行全员异或,就可得到a、b;
//那么如何进行分类呢?两个不同数字进行异或,得到结果的二进制位至少有一位为1,将其中的某个为1的二进制位记做第count位,那么a、b的第count二进制位一定是不同的;
//而相同数字的第count二进制位一定是相同的,不同数字的第count二进制位可能相同、也可能不同,所以,我们就可以按照这个方式进行分组,然后对两组元素进行全员异或,得到a、b;
#include<stdio.h> #include<stdlib.h> int* singleNumbers(int* nums, int numsSize, int* returnSize) { int* singlearr = (int*)calloc(2, sizeof(int));
if (singlearr == NULL)
return NULL;
*returnSize = 2; int sum = 0, count = 1; for (int i = 0; i < numsSize; i++) { sum ^= nums[i]; }
//找到二进制中第一个为1的位置 while ((sum & 1) == 0) { sum >>= 1; count *= 2; } for (int i = 0; i < numsSize; i++) {
//用count位是0还是1,来将数组分成两组 if ((nums[i] & count) == 0) { singlearr[0] ^= nums[i]; } else { singlearr[1] ^= nums[i]; } } return singlearr; } int main() { int arr[] = { 1,2,10,4,1,5,7,5,8,7,8,4,3,3 }; int ret = 0; int* retarr = singleNumbers(arr, sizeof(arr) / sizeof(arr[0]), &ret); for (int i = 0; i < 2; i++) { printf("%d\n", retarr[i]); } return 0; }
浙公网安备 33010602011771号