leetcode 面试题56 - I. 数组中数字出现的次数
题目描述:
一个整型数组 nums
里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是$O(n)$,空间复杂度是$O(1)$。
题解:
如果数组里面只有一个数字出现了一次,其余出现了两次,一遍异或就可以将其找出来。对于两个只出现一次的数,我们考虑将其分组,使得:
-
两个只出现一次的数字在不同的组中;
-
相同的数字会被分到相同的组中。
记两个只出现一次数字分别为$a$和$b$,那么所有数字异或的结果等于$a$和$b$异或的和,我们记为$x$。将$x$看作二进制$x_{k}x_{k-1}...x_{2}x{1}x{0}$,其中$x_{i} \in {0,1}$。对于$x$二进制每一位而言,表示的是$a$和$b$这一位是否相同,那么只要以$x$二进制位上任意一个为1的位置作为判断点,如果该位为0就分为第一组,为1就分给第二组,这样就能达到我们想要的分组效果。这样做的可行性很好分析,首先两个只出现一次的数字在不同的组中这一点很容易满足,那么相同的数字是否会分到相同的组中?相同的数字某一位二进制的值一定是相同的,所以一定会分到相同的组中。
AC代码:
class Solution { public: int del(int tmp) { int pos=0; while(tmp) { if(tmp%2 == 1) return pos; pos++; tmp/=2; } return -1; } vector<int> singleNumbers(vector<int>& nums) { int tmp = nums[0]; int Len = nums.size(); for(int i=1;i<Len;i++) tmp ^= nums[i]; int flag_pos = del(tmp); int g1,g2; int flag1,flag2; flag1 = flag2 = 1; for(auto &num:nums) { if( ((num>>flag_pos)&1) == 1) { if(flag1 == 1) { g1 = num; flag1 = -1; } else g1 ^= num; } else { if(flag2 == 1) { g2 = num; flag2 = -1; } else g2 ^= num; } } return {g1,g2}; } };