数组中只出现一次的两个数字:最直观的想法是,使用res表示结果,使用umap存储元素以及元素出现的次数,然后遍历array数组,记录各元素以及各元素出现的次数,接着遍历umap,找到只出现过一次的元素,并将其加入到res中,最后由于res中只有两个元素,直接判断排序即可。
vector<int> FindNumsAppearOnce(vector<int>& array) { vector<int> res; // 元素 元素出现的次数 unordered_map<int,int> umap; for(int i=0;i<array.size();i++) { //第一次出现 if(umap.find(array[i])==umap.end()) umap[array[i]]=1; //第n次出现 else umap[array[i]]++; } // 遍历寻找只出现过一次的元素 for(auto item:umap) if(item.second==1) res.push_back(item.first); // 两个元素 非降序排序 if(res[0]>res[1]) swap(res[0],res[1]); return res; }
优化:上述方法好像是较为通用的解题思路,但是有没有注意到,题目中特意说明,其他元素均出现两次,这是不是给我们的一个提示呢?位运算!异或运算!如果两个数相同,那么其位运算的结果为0,也就是说,如果只有一个只出现一次的数字时,其余均是出现两次时,我们可以将全部的数进行异或运算,那么最后得到的数字就是只出现一次的数字啦!可是,该题中有两个只出现一次的数字哎,这个怎么解决呢?尝试分组?将两个只出现一次的数字a和b分到两个不同的组中,且其他数字成对成对的被划分到不同的组,那么怎么分组呢?a和b的结果如果二进制的某一位为1,说明a和b对应位数不同,那么找到不同的这一位,然后以这一位是否为1来划分成两个数组,其中相同的数字自然会被划分到一边,而且a和b也会刚好被分开。总结下来具体的做法如下:首先遍历整个数组,将每个元素逐个异或运算,得到a异或b的结果;然后找到a异或b结果中第一位不相同的位,将所有元素分成两组;遍历整个数组对分开的数组单独进行异或;最后按照非降序次序输出。
vector<int> FindNumsAppearOnce(vector<int>& array) { // 结果数组 2个数 初始均为0 vector<int> res(2,0); //遍历数组得到a^b int awb=0; for(int i=0;i<array.size();i++) awb^=array[i]; // 找到两个数不同的一位 k表示不同那一位对应的数 int k=1; while((k&awb)==0) k<<=1; // 遍历数组进行分类 for(int i=0;i<array.size();i++) { if((k&array[i])==0) res[0]^=array[i]; else res[1]^=array[i]; } // 非降序次序 if(res[0]>res[1]) swap(res[0],res[1]); return res; }