題目: 給定一個非空整數數組,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。
說明: 你的算法應該具有線性時間複雜度。 你可以不使用額外空間來實現嗎?
示例:
示例 1:
輸入: [2,2,1]
輸出: 1
示例 2:
輸入: [4,1,2,1,2]
輸出: 4
一、哈希表 O(N) S(N)
這個思路很簡單:
- 先利用哈希表存儲數字和數字出現次數,<key,value>,key保存數值,value保存該數字出現次數;每次hash[nums[i]]++表示出現次數。
- 遍歷哈希表,可以選擇迭代器遍歷,或者使用auto變量即可以保存任何變量類型的變量來保存hash<key,value>,判斷value的值是否等於1,i.first得到key,i.second得到value,如果value==1,那麼返回key即爲答案。
int singleNumber(vector<int>& nums)
{
unordered_map<int,int>hash;
for(int i=0;i<nums.size();i++)
{
hash[nums[i]]++;
}
for(auto i:hash)//遍歷哈希表
{
if(i.second==1)//判斷出現次數
{
return i.first;
}
}
return 0;
}
但是這個解法使用了額外的空間,所以雖然可以通過但不是最優的。
二、排序 O(NlogN)
不使用額外空間的前提下,我們可以對數組進行排序:
- 利用C++自帶函數對數組排序,那麼相同的數字就會在集中在一起。
- 兩兩判斷是否相等,相等表示出現了2次,否則返回nums[i]即可,表示它是出現一次的。
- 注意,防止最後一個數字爲出現一次的,要進行對i的判斷,判斷它是否爲最後一個數字,是表示出現了一次則返回即可。
int singleNumber(vector<int>& nums)
{
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size();i+=2)
{
if( i==nums.size()-1||nums[i]!=nums[i+1] )//最後一個數字防止越界
{
return nums[i];
}
}
return 0;
}
排序最快的時間複雜度爲O(logN),雖然可以通過並不是線性時間複雜度。
三、最佳算法:位運算 O(N) S(1)
一定要記住,如果題目對時間,空間做出要求,利用一般解法無法做出,那麼要想到位運算,特別是異或。我們先看一下異或的性質:
- 交換律:p⊕q=q⊕p
- 結合律:p⊕(q⊕r)=(p⊕q)⊕r
- 恆等率:p⊕0=p
- 歸零率:p⊕p=0
那這個題目,只有一個數字出現了1次,其他都是2次,我們可以利用結合律,將出現偶數次數的數字異或,那麼結果爲0,如1⊕1=0;再和出現一次的⊕,那麼0⊕2=2,我們便可以找到這個重複的數字。記住,我們不用自己去調用結合律,系統自己會處理,如:數字【2,1,2】找出現一次的:
代碼如下:
//位運算異或交換律:1^1=0,1^0=1,1^2^1=1^1^2=2這樣就可以找到只出現一個的那個
int singleNumber(vector<int>& nums)
{
int sum=nums[0];;
for(int i=1;i<nums.size();i++)
{
sum=nums[i]^sum;
}
return sum;
}
這個就是最佳解法,要牢記⊕的特性。
加油哦!💪。