巧用位操作符之——^异或运算符

  1. 一道题目

题目:Single Number II Given an array of integers, every element appears three times except for one. Find that single one.
除了一个元素外,其它元素都是出现三次,求那个元素?

Note: Your algorithm should have a linear runtime complexity. Could
you implement it without using extra memory?

思路
题目对时间和空间复杂度进行了限制,利用位运算可以巧妙地解题。

异或位运算,相同则值为1,不同则值为0。所以数字和本身异或的结果为0。

更简单的题目:如果是除了一个元素,其它的都出现两次,那么数组汇总所有元素异或的结果就是所要找的元素。出现两次就是xor下。

对于出现3次的情况,还是用二进制位的方式来思考。

那么这些位,除去出现过一次的那个后,其他的都是3的倍数!- -我们把所有位1的个数mod 3,那么剩下的就是只出现过一次那个啦。

我们也没必要开个啥 int bit[32]的数组去统计的

模拟二进制加法,用两位来计数,到3就把该位清零。

bit2 bit1

bit1 如果该位来的是1 ,保持0,1,0,1。。。(也就是xor),如果是0就不变

当bit1=1的时候再来一个1,那么bit2=1

当这两个bit同时为1,说明这是3啦(二进制你想想嘛),该位清零。

class Solution {
public:
    int singleNumber(int A[], int n) {
        //总的来说,就是统计各个二进制位1出现的次数。
        //可以用one,two的每个二进制位分别代表对应位1出现的次数对三取模为1、2。
        //另外one,two的某个二进制位都为0时,则表示那位1出现的次数取模正好为0。
        int one = 0, two = 0; //刚开始在每位上1都没出现,所以都是0。
        int three = 0; //当one,two的某个二进制位都为1时,表明已经出现了三次,可以取模。

        for (int i = 0; i < n; ++i)
        {
            two |= one&A[i];
            one ^= A[i];
            three = one&two;
            //当出现三次后,one,two清0,相当于取模
            one &= ~three;
            two &= ~three;
        }

        return one|two; //因为不知道那个数是出现一次还是两次,所以将出现一次或两次的都返回
    }
};

更简洁的写法

public int singleNumber(int[] A) {
    int ones = 0, twos = 0;
    for(int i = 0; i < A.length; i++){
        ones = (ones ^ A[i]) & ~twos;
        twos = (twos ^ A[i]) & ~ones;
    }
    return ones;
}
  1. 交换两个数值
void Swap(int &a, int &b) { if (a != b) { a ^= b; //a = a^b; b ^= a; //b = b^a ==> b = b^(a^b) = b^(b^a) = b^b^a = 0^a = a; a ^= b; //a = a^b = a^a==> a = (a^b)^a = a^b^a = a^a^b = b; } }

你可能感兴趣的:(异或,位运算符)