题目:
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
预备知识:
异或运算有以下三个性质。
- 1、任何数和 0 做异或运算,结果仍然是原来的数。例如 :x^0 = x
- 2、任何数和其自身做异或运算,结果是 0。例如:x^x=0
- 3、异或运算满足交换律和结合律。例如:x^a^a^x=x^(a^a^x)=x^(0^x)=x^x=0
实际上如果对一个数连续异或两次相同的数,其数不变。如a^b^b=a;
题解:
方法一:位运算。使用异或运算的三个性质,让所有的数取异或。根据异或运算三个性质,所有数组中只要有相同的数字就会变成0,最后剩下一个不同的数字和0取异或扔为它本身。这数字就是我们要求的。
代码:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int t=0;
for(int i=0;i<nums.size();i++)
{
t^=nums[i];
}
return t;
}
};
方法二:利用集合set,只保留数组中各种不同样本的一份(set集合相同数字会覆盖),然后让集合的数字之和乘2,这样我们得到的是所有原始数组元素的两倍(也就是那个不同的数字我们把它当成了两份,相同的数字相当于恢复成原来的两份)。相当于这个数组有两个不同的数字,其他数字相等。现在让其减去原始数组,就能得到这个不同的数字了。
例子:假设我们原始数组是(1,2,2,3,3) ,和是1+2+2+3+3=11。用set保存的时候是(1,2,3),让set中的元素求和乘2,得到(1+2+3)*2=12(这里表示成数组就是(1,1,2,2,3,3),比原始数组多增加了一个不同数字“1”)。所以(1,1,2,2,3,3) -(1,2,2,3,3)=1,就能得我们要找的值。
代码:
class Solution {
public:
int singleNumber(vector<int>& nums) {
set<int>se;
int sum_of_nums=0,sum_of_se=0;
for(int i=0;i<nums.size();i++)
{
se.insert(nums[i]);
sum_of_nums+=nums[i];
}
for(set<int>::iterator it=se.begin();it!=se.end();it++)
{
sum_of_se+=*it;
}
return sum_of_se*2-sum_of_nums;
}
};