方法一:
- 直接使用哈希表,用哈希表的额外内存空间来记住当前数字出现的次数,出现两次的会被删除,只剩下两个出现一次的数字。
代码如下:
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param array int整型vector * @return int整型vector */ vector<int> FindNumsAppearOnce(vector<int>& array) { // write code here //使用哈希表的方式 unordered_set<int> s; for(int x:array){ if(!s.count(x)){ s.insert(x); }else{ s.erase(x); } } auto it=s.begin(); int x=*it; it++; int y=*it; return vector<int>{y,x}; } };
复杂度分析:
时间复杂度:O(n),n为数字个数,遍历一次。
空间复杂度:O(n),哈希表内所需的最大内存空间为n/2+1。
方法二:
解题思路:
- 除了这两个只出现一个的两个数字外,其他数字都是出现的两次,可以考虑利用该特性,使用位运算的方法解决。
- 如果题目中出现一次的数字只有一个,那么把所有数进行异或就能得到答案,因为相同的数异或后为0。而本题中出现一次的数字有两个,设为x,y,那么要想得到答案,需要进行分组异或,假设将所有数字分为A,B组。那么A,B组需要满足的条件为:
1.x在A组,y在B组。
2.成对出现的数字必须在同一组。 - 为满足该条件,采取的办法为:先将所有数异或,得到的数z=x^y,找到z的任意不为0的一位,该位说明x,y在此位上不同。遍历数组,该位为1的数字放入A组,该位为0的数字放入B组。满足了上述1,2条件。
图解分析:
代码如下:
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param array int整型vector * @return int整型vector */ vector<int> FindNumsAppearOnce(vector<int>& array) { // write code here //所有数进行异或 int tmp=0; for(int x:array) tmp^=x; //寻找不为0的数位 int diff=1; while(!(diff&tmp)) diff<<=1; //分成两组分别异或 int a=0,b=0; for(int x:array){ if(x&diff) a^=x; else b^=x; } if(a<=b) return vector<int>{a,b}; else return vector<int>{b,a}; } };
复杂度分析:
时间复杂度:O(n),n为数字个数,遍历数组两次。
空间复杂度:O(1),常数个临时变量。