- 一道題目
題目: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;
}
- 交換兩個數值
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;
}
}