巧用位操作符之——^異或運算符

  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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章