题目描述
Given an array of numbers nums
, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.
题目大意
给定一个数组,该数组存在两个数字只出现了一次,其余的数字在该数组中出现了两次,找到数组中的两个只出现了一次的数字。
示例
E1
解题思路
Solution1
用一个set类型保存访问过的数字,每访问到一个set中没有的数字则将其插入set中,若set中已经存在了该数字,则将set中的该数字删除。即最后set存在的两个数字即为结果。
Solution2
一个巧妙的方法,将所有数字异或一遍,即可得到两个出现一次数字的异或。再将得到的异或结果,除了最后一个非零位,其余非零位全部置零。最后遍历一遍数组中的数字,将数字分为两组,与该异或结果按位与是否为零进行分开,则分开后的所有数字做异或,最后可得到两个结果数字。
复杂度分析
时间复杂度:O(NN)
空间复杂度:O(N1)
代码1
class Solution { public: vector<int> singleNumber(vector<int>& nums) { set<int> visit; // 遍历一边数组 for(int num : nums) { // 查找set中是否已有该数字 auto iter = visit.find(num); // 若没有,则将其插入set if(iter == visit.end()) visit.insert(num); // 否则,将其删除 else visit.erase(iter); } vector<int> res; // 将set中剩余的两个数字放入结果数组 for(auto iter = visit.begin(); iter != visit.end(); ++iter) res.push_back(*iter); return res; } };
代码2
class Solution { public: vector<int> singleNumber(vector<int>& nums) { // 将所有数字异或,返回得到的异或的结果 int dif = accumulate(nums.begin(), nums.end(), 0, bit_xor<int>()); // 只保留该异或结果的其中一个非零位,其余置零 dif &= -dif; vector<int> res = {0, 0}; // 遍历一边数组,将数组中的数字分类 for(int num : nums) { // 若该数字与dif按位与不为零,则将其异或的结果保留在res[0]中 if(num & dif) res[0] ^= num; // 否则,将其保留到res[1]中 else res[1] ^= num; } return res; } };