一.题目描述
Nc75数组中只出现一次的两个数字
题目链接:
https://www.nowcoder.com/practice/389fc1c3d3be4479a154f63f495abff8?tpId=188&&tqId=38602&rp=1&ru=/activity/oj&qru=/ta/job-code-high-week/question-ranking
一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
二.算法(暴力模拟)
要找到数组中只出现一次的两个数字,最容易想到的就是对整个数组进行遍历,然后找出两个只出现一次的数字。
利用c++sTL中的map可以很好的解决这个问题,下面是完整代码:
class Solution { public: vector<int> FindNumsAppearOnce(vector<int>& array) { map<int,int>mp; for(int i=0;i<array.size();i++){ mp[array[i]]++; } vector<int>q;//返回最后的两个数字 for(auto &i:mp){ if(i.second==1){ q.push_back(i.first);/要是只出现一次 那就入队 } } sort(q.begin(),q.end());//对返回的数组进行排序 return q; } };
时间复杂度:o(n)
空间复杂度:o(n*n)需要额外开辟空间返回结果和记录出现次数
优缺点:时间复杂度高,但是便于实现。
三.算法(位运算)
如上面例子中的数组,我们每做一次异或运算,最后的1会被消去,只剩下4和6的异或结果xor。
然后我们再找这个xor的最后一个1的位置:xor-xor&(xor-1)
因为根据题目要求有两个数是不重复的,所以最后一个1的位置说明这两个数在这个位置上的二进制的数字是不同的,我们可以根据这个特性给它们分别存放在容量为2的数组的不同的位置中。得到最后的1这个数字之后,用这个数再次与整个数组进行异或运算,重复的数会被消去,只剩下那个唯一的值就是结果。下面给出完整代码:
class Solution { public: vector<int> FindNumsAppearOnce(vector<int>& array) { int x=array[0]; for(int i=1;i<array.size();i++){ x^=array[i]; } //找到二进制中最右边的1 x-=x&(x-1); vector<int>q; //提前放入两个数据 防止段错误 q.push_back(0); q.push_back(0); for(int i=0;i<array.size();i++){ //根据他们是1还是0 来分配在数组q中的位置 if((x&array[i])==0) q[0]^=array[i]; else q[1]^=array[i]; } //排序 sort(q.begin(),q.end()); return q; } };
时间复杂度:o(n)
空间复杂度:o(n) 需要额外空间来存在返回结果
优缺点:空间利用率低,但是实现起来复杂