leetcode : Single Number
这个题一个有三道:
Single Number i:
给n个整数,其中有一个数只出现了一次,其他的数都出现了两次,求那个single number,这个很简单,把所有的数字做一下异或,得到的结果就是那个single dog。
Single Number ii:
给n个整数,其中所有的整数都出现了三次,除了一个single number。
这里有两个思路,第一种是对每一个二进制位统计出现次数,因为除了single number以外的数都出现了三次,我们可以统计每个二进制位中1出现的次数k,而k%3就是single number在这一位贡献的1的个数。
AC代码:
class Solution { public: int singleNumber(int A[], int n) { int bitCount = sizeof(int) * 8,result = 0; int *arr = new int[bitCount]; for(int i = 0; i < bitCount; ++i){ arr[i] = 0; } for(int i = 0; i < n; ++i){ for(int j = 0; j < bitCount; ++j){ arr[j] += (A[i] >> j) & 1; } } for(int i = 0; i < bitCount ; ++i){ result |= (arr[i]%3) << i; } delete arr; return result; } };
但是这么写比较慢,因为对每个n都要做32次位移分别统计每一位是否为1,可以尝试改进一下,毕竟位操作直接用个数组存每一位出现的次数有点low。
所以尝试用一个整数保存每一位出现的次数。想办法把出现三次变成出现四次,再异或到一起就可以了。
可以用三个数来代替这个数组:
对于one中每个为1的位,表示到当前为止,这些位上出现了k*3 + 1个1,
对于two中每个为1的位,表示到目前为止,这些位上出现可k*3 + 2个1,three同理
AC代码:
class Solution { public: int singleNumber(int A[], int n) { int one=0, two=0, three=0; for(int i=0; i<n; i++){ two |= one&A[i]; one^=A[i]; //cout<<one<<endl; three=one&two; one&= ~three; two&= ~three; } return one; } };
解释一下这个代码:
two |= one&A[i]
这里 |=是为了置1,即把那些同时在one 和 A[i]中的1放进two中(已经出现了3*k + 1次,又出现了一次,于是变成了3*k + 2次,放在two中记录)
one ^= A[i],这里比较清楚,一开始出现了0次,后来又出现了一次才放进one,否则将这一位清零(共计出现两次,所以不在one中)
three = one&two ,这里是有点容易迷惑的,某一位第3*k次出现时,首先会将one置1,然而它并不会影响two,所以three就是那些已经出现了3K+2数,又出现了一次时,记录下来。
这也意味着将one和two中的1 “吸收”进了three,所以要把one 和two中这些位清0,所以ont &= ~three, two &= ~three.
这个方法很扯淡,但是很快且省空间- -!
Single Number iii
n个整数中,每个数都出现了两次,除了某两个数都只出现了一次,这道题比起single number i 要难一些,在一堆情侣中找一只单身狗自然要比找一对基佬容易些的,思路的关键在与将问题转换为single number i
就是想办法把这两个single number分开,假设他们分别为A,B,那么对所有的数异或就得到A ^ B,所以这个A^B必然是不等于0的,因为A B都只出现了一次,相等就变成出现两次了,那么随便从A ^ B中找一个是1的位,不妨设为第k位,那么可以将这个n个数分成两拨,一波是第k位为1的,另一波是第k位为0的,那么问题就变成Single Number i了。
代码中使用mask = AorB & (~(AorB-1))取得了一个屏蔽字,只保留最左的1,其他位置0.
AC代码:
class Solution { public: vector<int> singleNumber(vector<int>& nums) { unsigned int AorB = 0; for (int elem : nums) { AorB ^= elem; } int mask = AxorB & (~(AxorB-1));; int A = 0, B = 0; for (int elem : nums) { if (elem & mask) { A ^= elem; } else { B ^= elem; } } return vector<int>{A, B}; } };
浙公网安备 33010602011771号