標籤:位元運算 面試
情形一:數組中所有數都出現兩次,只有一個數出現一次
情形二:數組中所有數都出現兩次,只有兩個數出現一次
情形一二很多地方都有說明,這裡就不囉嗦了,有一點需要注意:當知道未經處理資料時,可以使用解方程的方法,這樣可以把上面的情形無線推廣,具體見編程之美
情形三:數組中所有數都出現三次,只有一個數出現一次
方法一:如果數組中的元素都是三個三個出現的,那麼從二進位表示的角度,每個位上的1加起來,應該可以整除3。如果有一個數x只出現一次,會是什麼情況呢?
如果某個特定位上的1加起來,可以被3整除,說明對應x的那位是0,因為如果是1,不可能被3整除如果某個特定位上的1加起來,不可以被3整除,說明對應x的那位是1
根據上面的描述,我們可以開闢一個大小為32的數組,第0個元素表示,A中所有元素的二進位表示的最低位的和,依次類推。最後,再轉換為十進位數即可。這裡要說明的是,用一個大小為32的整數數組表示,同樣空間是O(1)的。
int FindNumber(int a[], int n) { int bits[32]; int i, j; // 累加數組中所有數位二進位位 memset(bits, 0, 32 * sizeof(int)); for (i = 0; i < n; i++) {for (j = 0; j < 32; j++) {bits[j] += ((a[i] >> j) & 1); }}int result = 0; for (j = 0; j < 32; j++) {if (bits[j] % 3 != 0) result += (1 << j); }return result; } 方法二:參考這裡
Single Number的本質,就是用一個數記錄每個bit出現的次數,如果一個bit出現兩次就歸0,這種運算採用二進位底下的位操作^是很自然的。Single Number II中,如果能定義三進位底下的某種位操作,也可以達到相同的效果,但是這個東西沒有現成的可用。
我們換個思路,Single Number II中想要記錄每個bit出現的次數,一個數搞不定就加兩個數,用ones來記錄只出現過一次的bits,用twos來記錄只出現過兩次的bits,ones&twos實際上就記錄了出現過三次的bits,這時候我們來類比進行出現3次就抵消為0的操作,抹去ones和twos中都為1的bits。
int singleNumber(vector<int>& data){int ones = 0,twos = 0,threes = 0,length = data.size(),i;for (i = 0;i < length;i++){twos |= ones & data[i];//記錄只出現過2次的bits,要在更新ones前面更新twosones ^= data[i];//記錄只出現過1次的bitsthrees = ones & twos;//ones和twos中都為1即出現了3次ones &= ~threes;//抹去出現了3次的bits,相當於模3運算twos &= ~threes;}return ones;//返回只出現一次的}
情形四:數組中所有數都出現三次,只有一個數出現兩次
按照情形三的方法二,只要返回twos即可,原理是一樣的
位元運算總結