問題1
給定一整形數組,已知該數組中一個數出現了一次,其餘的數出現了偶數次,找到這個出現一次的數
解法一:使用hashMap記錄次數,然後返回只出現一次的那個數
代碼如下:
public int singleNumber(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
for(int num : nums) {
int val = map.containsKey(num) ? map.get(num) + 1 : 1;
map.put(num, val);
}
for(int num : nums) {
if(map.get(num) == 1) {
return num;
}
}
return 0;
}
時間複雜度爲O(N),額外空間複雜度O(N)
解法二:使用位運算。我們知道兩個相同的數進行異或操作後的結果是0,任何數和0異或的結果是它本身,異或操作亦具有交換律。因此我們只需讓數組中所有數異或到一起,結果即爲所求。
代碼如下:
public int singleNumber(int[] nums) {
int result = 0;
for(int num : nums){
result ^= num;
}
return result;
}
時間複雜度O(N),額外空間複雜度O(1)。
問題2
給定一整型數組,已知其存在兩個數出現了一次,其它數出現了偶數次,找到那連個出現一次的數。
該問題依然可以使用HashMap進行求解,解法與問題一相同,不加贅述了。
該問題中由於含有兩個出現一次的數,如直接全部異或的到的結果爲這兩數的異或,因此無法直接按問題一解法求解。
一個想法是將這兩個數分開,分別求解,我們知道若兩數相同則其在任一位都相同,若兩數不同,則總是存在一位不同的位。由於我們已經得到了這兩數的異或記做XOR1,找到XOR1中爲1的那一位,可得該位上這兩數一定不同,因此可以通過該位是否爲1可以將數組分爲兩塊,分別對這兩塊求異或即爲所求。
實現代碼如下:
public int[] singleNumber(int[] nums) {
int xor1 = 0;
for(int num : nums){
xor1 ^= num;
}
int number = 0; // 存儲爲1的位數
for(int i = 0; i < 32; i++){
if((xor1 & 1) == 1){
number = i;
break;
}
xor1 = xor1 >> 1;
}
int val1 = 0, val2 = 0;
for(int num : nums){
if(((num >> number) & 1) == 1){
val1 ^= num;
}else{
val2 ^= num;
}
}
return new int[] {val1, val2};
}