方法一:

  • 直接使用哈希表,用哈希表的额外内存空间来记住当前数字出现的次数,出现两次的会被删除,只剩下两个出现一次的数字。

代码如下:

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),常数个临时变量。