只出現一次的數字 簡單、只出現一次的數字II 中等、只出現一次的數字III 中等
NO.136 只出現一次的數字 簡單
思路一:異或
public int singleNumber(int[] nums) {
int ans = 0;
for (int num : nums) {
ans^=num;
}
return ans;
}
時間複雜度:O(n) 空間複雜度:O(1)
NO.137 只出現一次的數字II 中等
思路一:按位統計 遍歷數組中每個元素的每一位(除了符號位),統計每一位上 1 的個數,最後再將每一位上 1的數量取模 3,得到最終的結果。例如:
nums[2,2,3,2]=nums[0010,0010,0011,0010]
統計每一位上1的次數:0041
每一位上的數字取模3:0011 = 3
不難理解,剩下的就是如何實現。
對每個數字 num 的右移待統計位數,再對 1 求與,可以得到待統計位上的是 1 還是 0。
統計完某一位上 1 的數量之後,取模 3 結果一定是 1 或 0 ,再左移回原本的位上,最後通過異或運算存到結果中。還是上例:
nums[2,2,3,2]=nums[0010,0010,0011,0010]
統計第0位上1的次數:1 取模3左移回到原位:0001 異或存回res:0001
統計第1位上1的次數:4 取模3左移回到原位:0010 異或存回res:0011
統計第3位上1的次數:0 取模3左移回到原位:0000 異或存回res:0011
統計第4位上1的次數:0 取模3左移回到原位:0000 異或存回res:0011
最終結果res:0011 = 3
public int singleNumber(int[] nums) {
int res = 0;
//分別統計每一位上 1 的個數
for (int i = 0; i < 32; i++) {
int count = 0;
for (int num : nums) {
count += (num >> i) & 1;
}
//個數取模 3 再還原回原位,最後保存至res
res ^= (count % 3) << i;
}
return res;
}
時間複雜度:O(n) 32次遍歷O(32n)。
空間複雜度:O(1)
NO.260 只出現一次的數字III 中等
思路一:分組異或 劍指Offer 第 56 題一樣。
如果只有一個數字出現過一次,直接將數組遍歷依次異或,最終的到的結果就是隻出現過一次的數字。因爲異或運算,相同爲 0,不同爲 1。
但是本題有兩個只出現一次的數字 a、b,按照上述方法得到的結果一定是a^b。
如果可以將 nums 分爲兩組, a 和 b分別再不同的組,其餘相同的元素一定在同一個組。這樣,我們就可以像開頭提到的方法一樣,將兩組分別異或,兩組最後得到的結果,一定就是 a 和 b 。
重點在於如何分組:
- 先將 nums 遍歷依次異或,得到 res=a^b。
- 與運算,拿到 res 任意一個等於 1 的位 h。
- 遍歷 nums 分別和 h 進行與運算,等於 0 的分一組進行異或,不等於 0 的分一組進行異或,最後兩組的結果就是 a 和 b。
public int[] singleNumber(int[] nums) {
//得到 a^b
int n = 0;
for (int num : nums) {
n ^= num;
}
//得到n中任意一位1的位置
int h = 1;
while ((h & n) == 0) {
h <<= 1;
}
//分組異或
int a = 0, b = 0;
for (int num : nums) {
if ((num & h) == 0) {
a ^= num;
} else {
b ^= num;
}
}
return new int[]{a, b};
}
時間複雜度:O(n) 空間複雜度:O(1)
本人菜鳥,有錯誤請告知,感激不盡!
更多題解和源碼:github