方法一:哈希表
可以使用哈希映射统计数组中每一个元素出现的次数
统计之后再进行遍历。
vector<int> singleNumber(vector<int>&nums){
unordered_map<int,int> freq;
for(int num:nums){
++freq[num];
}
vector<int> ans;
for(const auto& [num,occ]:freq){
if(occ==1){
ans.push_back(num);
}
}
return ans;
}
时间复杂度和空间复杂度都是O(n)
方法二:位运算
假设数组 \textit{nums}nums 中只出现一次的元素分别是 x_1和 x_2 。如果把 nums 中的所有元素全部异或起来,得到结果 x,那么一定有:
x=x1⊕x2
其中 ⊕ 表示异或运算。这是因为nums 中出现两次的元素都会因为异或运算的性质 a⊕b⊕b=a 抵消掉,那么最终的结果就只剩下 x1 和 x2 的异或和。
x 显然不会等于 0,因为如果x=0,那么说明 x_1 = x_2,这样 x_1 和 x_2就不是只出现一次的数字了。因此,我们可以使用位运算x & -x 取出 x 的二进制表示中最低位那个 1,设其为第 l位,那么 x_1和 x_2中的某一个数的二进制表示的第 l 位为 0,另一个数的二进制表示的第l位为 1。在这种情况下,x1⊕x2的二进制表示的第 l 位才能为 1。
这样一来,我们就可以把 nums 中的所有元素分成两类,其中一类包含所有二进制表示的第 l 位为 0 的数,另一类包含所有二进制表示的第 l 位为 1 的数。可以发现:
1.对于任意一个在数组 nums 中出现两次的元素,该元素的两次出现会被包含在同一类中;
2.对于任意一个在数组nums 中只出现了一次的元素 ,它们会被包含在不同类中。
因此将每一类元素全部异或起来,一类就可以得到x1,另一类就可以得到x2
vector<int> singleNumber(vector<int>& nums){
int xornum=0;
for(int num:nums){
xorsum ^=num;
}
//防止溢出
int lsb=(xorsum=INT_MIN?xornum:xorsum&(-xorsum));
int type1=0,type2=0;
for(int num:nums){
if (num&lsb){
type1^=num;
}
else{
type2^=num;
}
}
return {type1,type2};
参考来源
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/single-number-iii/solution/zhi-chu-xian-yi-ci-de-shu-zi-iii-by-leet-4i8e/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。