情形一:数组中所有数都出现两次,只有一个数出现一次
情形二:数组中所有数都出现两次,只有两个数出现一次
情形一二很多地方都有说明,这里就不啰嗦了,有一点需要注意:当知道原始数据时,可以使用解方程的方法,这样可以把上面的情形无线推广,具体见编程之美
情形三:数组中所有数都出现三次,只有一个数出现一次
方法一:如果数组中的元素都是三个三个出现的,那么从二进制表示的角度,每个位上的1加起来,应该可以整除3。如果有一个数x只出现一次,会是什么情况呢?
如果某个特定位上的1加起来,可以被3整除,说明对应x的那位是0,因为如果是1,不可能被3整除
如果某个特定位上的1加起来,不可以被3整除,说明对应x的那位是1
根据上面的描述,我们可以开辟一个大小为32的数组,第0个元素表示,A中所有元素的二进制表示的最低位的和,依次类推。最后,再转换为十进制数即可。这里要说明的是,用一个大小为32的整数数组表示,同样空间是O(1)的。
int FindNumber(int a[], int n) { int bits[32]; int i, j; // 累加数组中所有数字的二进制位 memset(bits, 0, 32 * sizeof(int)); for (i = 0; i < n; i++) { for (j = 0; j < 32; j++) { bits[j] += ((a[i] >> j) & 1); } } int result = 0; for (j = 0; j < 32; j++) { if (bits[j] % 3 != 0) result += (1 << j); } return result; }
方法二:参考这里
Single Number的本质,就是用一个数记录每个bit出现的次数,如果一个bit出现两次就归0,这种运算采用二进制底下的位操作^是很自然的。Single Number II中,如果能定义三进制底下的某种位操作,也可以达到相同的效果,但是这个东西没有现成的可用。
我们换个思路,Single Number II中想要记录每个bit出现的次数,一个数搞不定就加两个数,用ones来记录只出现过一次的bits,用twos来记录只出现过两次的bits,ones&twos实际上就记录了出现过三次的bits,这时候我们来模拟进行出现3次就抵消为0的操作,抹去ones和twos中都为1的bits。
int singleNumber(vector<int>& data) { int ones = 0,twos = 0,threes = 0,length = data.size(),i; for (i = 0;i < length;i++) { twos |= ones & data[i]; //记录只出现过2次的bits,要在更新ones前面更新twos ones ^= data[i]; //记录只出现过1次的bits threes = ones & twos; //ones和twos中都为1即出现了3次 ones &= ~threes; //抹去出现了3次的bits,相当于模3运算 twos &= ~threes; } return ones;//返回只出现一次的 }
情形四:数组中所有数都出现三次,只有一个数出现两次
按照情形三的方法二,只要返回twos即可,原理是一样的
时间: 2024-10-12 16:34:18