I 一个数组,就一个数字出现1次,其他出现2次
思路:采用异或^位运算,两个相同的数做异或,得到的结果是0,0与A异或得到A,那么把数组里面的数一起异或一遍,就会得到最后出现一次的数。
II 一个数组,两个不同的数字出现1次,其他出现2次
思路:仍然采用异或^位运算,两个相同的数做异或,得到的结果是0,0与C异或得到C,那么把数组里面的数一起异或一遍,那么最后就会得到 res = A异或B,也就是两个只出现1次的数的异或结果且非0,然后知道res中bit位任意出现1的位置就是A和B在这个bit位置 是不同造成(一个0一个1)的,因为其他数出现两次,在这个bit位置最后异或的结果是肯定是由A和B在这个位置不同造成的,接下来按照这个位置是0还是1对原数组进行分组异或,分别得到的值就是A和B。
II 一个数组,就一个数字出现1次,其他出现3次
思路:这个就很困难了,采用异或是无法完成的,走入死胡同。查资料小半天才明白别人的方法。对数的每个bit位1出现的次数模拟三进制加法,这样的话,那么对所有的数 进行相应bit位的1出现的次数进行三进制加法,最后就会归0,因为有一个数是出现1次,那么最后加法的结果就是这个数。
模拟三进制。00 01 10 11 代表 0 1 2 3. 这里是四个数是因为次数出现位11的时候我们就清0,11只是我们中间状态,进行判断清0的。那么就需要两个位来进行模拟
twos , ones (ones是低位, twos是高位) ,当twos , ones 同时为1说明这个bit位上的1出现了3次,就把该位清0,这样循环完所有数组,ones就是最后的结果
int singleNumber(vector<int> nums) {
int size = nums.size();
int ones = 0, int twos = 0;
int threes=0;
for(int i=0 ; i < size ;++i)
{ //twos ^= (ones & nums[i])采用异或也可以,
//因为ones & nums[i]为1的情况就只有相同的数出现了两次的时候。
twos |= (ones & nums[i])//ones & nums[i]是获得是否产生进位
//因为刚好二进制的话出现两个11 two=1了
//1 0 twos就无法获得该进位 twos=0
ones ^= nums[i] //获得该低位的结果 如果为1^1,因为进位已经给了twos 所以ones = 0;
threes = ~(twos&ones )//清0,因为两个位同时为1说明出现了3次,清0
ones &= threes ;//清0出现3次的位
twos &= threes ;//清0出现3次的位
}
}