【力扣】136. 只出现一次的数字

题目: 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明: 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例:
示例 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;
}

这个就是最佳解法,要牢记⊕的特性。

加油哦!💪。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章