題目
陣列中數字出現的次數
題意
一個整型陣列 nums 裡除兩個數字之外,其他數字都出現了兩次。請寫程式找出這兩個只出現一次的數字。要求時間複雜度是O(n),空間複雜度是O(1)
分析
如果是數值中只有一個這樣的數字,我們應該怎麼做?
根據位運算我們可以知道,a ^ a = 0, 0 ^ a = a, a ^ b ^ c = a ^ c ^ b
我們只要將陣列遍歷異或一遍最後的異或值就是這樣的一個數字
此題目中有兩個這樣的數字a, b,因此我們按上述操作得到的結果是這兩個數字的異或值,不是我們需要的答案
因此我們需要將陣列分為兩個陣列,滿足下列的要求
- 相同的數字要分到同一個陣列中
- a, b要分到不同的陣列中
只要滿足上述的兩個條件,就能分組異或,分別得到a, b
要將a, b分至不同的陣列中,就要找到他們的不同點加以區分,有上述我們知道,遍歷異或的到的是a, b的異或值
由異或的計算過程可知,只有在其a, b的二進位制位不相等的位置才能二進位制位是1,因此我們只要找到a ^ b的值的二進位制位上為1的位,這樣就滿足了條件2
因為相同的數在其對應的二進位制位上的值是相同的所以必然會被分到一組,滿足條件1
演算法
先對所有數字進行一次異或,得到兩個出現一次的數字的異或值。
在異或結果中找到任意為 1 的位(其他位為0),這裡使用不為0的最低位(利用lowbit做)。
根據這一位對所有的數字進行分組。
在每個組內進行異或操作,得到兩個數字。
class Solution {
public int[] singleNumbers(int[] nums) {
int[] res = new int[2];
int ans = 0;
for(int item : nums) ans ^= item;
int lowbit = ans & (-ans);
for(int item : nums){
if((lowbit & item) == 0)
res[0] ^= item;
}
res[1] = ans ^ res[0];//自反性
return res;
}
}