1. 程式人生 > >劍指offer-陣列中只出現一次的數字(陣列)

劍指offer-陣列中只出現一次的數字(陣列)

題目描述

一個整型數組裡除了兩個數字之外,其他的數字都出現了偶數次。請寫程式找出這兩個只出現一次的數字。

這題想到用map,類似於“陣列中出現次數超過一半的陣列”https://blog.csdn.net/Mr_xuexi/article/details/84555464

其中,data[i]是key值,出現次數count為value值。

方法一:這個方法比較容易想到,思路也比較簡單。

這個就是典型的用空間換時間了,時間複雜度是O(n)。

class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        if(data.size()<2)
            return ;
        map<int,int>m;
        for(int i=0;i<data.size();i++)
            m[data[i]]++;
        vector<int> res;
        for(int i=0;i<data.size();i++)
            if(m[data[i]]==1)
                res.push_back(data[i]);
        *num1=res[0];
        *num2=res[1];
    }
};

方法二:異或法,這個方法是在討論區看到的!(這個思路很新奇)

這個方法是,先將所有的數字一起進行異或處理,自己與自己異或是0。 那麼最後的結果temp就是不相同的兩個數字的異或結果。用這個結果,將陣列中的數字分為兩個部分。那麼怎麼分呢?

先判斷temp中最低為1的是哪一位,兩個不同的數異或,結果至少是xx1xx之類的(一定含有至少一個1,不然就全為0了)找到這個1(假設是從右往左數第三位),這說明對於這兩個不同的數a和b,a的第三位是1,b的第三位是0(或者a的第三位是0,b的第三位是1,意思一樣的)。

那麼就可以把這個陣列中的數,根據數的第三位是0或者是1分為兩部分,第三位是1的是一部分,是0的為另外一部分。其中相同的數肯定會被分到同一組(相同的數肯定每一位都是相同的啊!),而a,b因為第三位不同,會被分到不同的兩組中。那麼這兩組就分別只包含一個單獨的數了,也就是分為了類似{a,xxxxxx}和{b,xxxxxx}。這樣就可以對著兩組分別再一次用異或的方法,相同的數異或得到0,最後異或的結果分別是a,和b。

對於異或得到不同的一個數,大家玩過撲克牌的一種玩法抽烏龜嗎,這就是玩抽烏龜的那種感覺!相同的牌可以想象是被扔出去了!反正異或之後都是0!最後就只剩一個不同的數就是烏龜!

class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        if(data.size()<2)
            return ;
        int len=data.size();
		int temp=0;
		int index=1;
		for(int i=0;i<len;i++)
			temp^=data[i]; //自己跟自己異或是0,temp是不同的那兩個數字的異或結果
		//找到temp中最低為1的一位(也就是兩個數中相應位的數不同的一位)
		while((temp&index)==0)
			index<<=1;
		*num1=*num2=0;
		for(int i=0;i<len;i++)
		{
			if((data[i]&index)==0) //這裡把data分為了兩部分,與index有相同位為1的為一部分 
				*num1^=data[i]; //對這部分進行異或
			else
				*num2^=data[i]; 
		}
    }
};

空間複雜度是O(n),時間複雜度也比方法一要低。