方法一:暴力
1.结题思路
暴力法统计元素出现次数并输出。
2.解法
暴力,遍历vector,并用map或set统计每个元素的出现次数再找出出现次数为1的数即可。
3.具体代码
vector<int> FindNumsAppearOnce(vector<int>& array) { vector<int>ans; map<int,int>m; for(vector<int>::iterator it=array.begin();it!=array.end();it++){//统计每个数字出现的次数 m[*it]++; } for(vector<int>::iterator it=array.begin();it!=array.end();it++){//找出出现次数为1的元素 if(m[*it]==1)ans.push_back(*it); } return ans; }
4.时间复杂度和空间复杂度分析
时间复杂度:O(nlogn),n是数组元素个数,仅遍历了两次vector数组,使用map有序,时间复杂度为O(nlogn)。
空间复杂度:O(1),只存了两个出现一次的整形数。
方法二:位运算
1.结题思路
数组中所有元素按位异或,也即两个出现次数为一的数的异或,异或的好处在于消去了出现次数为二的元素,只保留下出现为1的数的特征。再根据特征求解即可。
2.解法
- 所有元素按位异或,得到两个出现次数为一的数的异或。
- 接着对两个出现次数为一的数的异或取lowbi运算;
lowbit(n):非负整数n在二进制表示下“最低位的1及其后面所有的0”构成的数值。
lowbit(n)=n&(~n+1)=n&(-n); - 由lowbit运算确定出两个出现次数为一的数不相同的一位,并根据该位对所有数组元素进行分组,必能将这两个数分到两组里去,其余元素出现次数为2相异或必为0,0再与这两个数分别异或就等于这两个数本身。
3.图解
4.具体代码
vector<int> FindNumsAppearOnce(vector<int>& array) { vector<int>ans; int temp=0;//数组中所有元素按位异或 for(int i=0;i<array.size();i++){ temp^=array[i]; } temp=temp&(-temp);//temp在二进制表示下“最低位的1及其后面所有的0”构成的数 int a=0,b=0;//0与任何数异或等于任何数本身 for(int i=0;i<array.size();i++){//将vector中元素根据temp二进制中1所在位为1或为0分成两组 if((array[i]&temp)==0)a^=array[i];//对应位为0,相异或为0 else b^=array[i];//对应位为1,相异或为temp } if(a>b)swap(a,b);//按大小加入ans ans.push_back(a);ans.push_back(b); return ans; }
5.时间复杂度和空间复杂度分析
时间复杂度:O(n),n是数组元素个数,代码中仅遍历了两次数组。
空间复杂度:O(1),只用到了ab两个常数级别的整形数据。