剑指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),时间复杂度也比方法一要低。

猜你喜欢

转载自blog.csdn.net/Mr_xuexi/article/details/84591642
今日推荐