思路:

题目的主要信息:

  • 数组有n个无序数字,其中有一个数字只出现了1次,其他数字都出现了k次
  • 需要找到只出现了一次的数字
  • k>1,k无特殊情况,只需要考虑空数组

方法一:排序法
具体做法:
首先对数字进行排序,使之呈现递增的状态,这样相同的数字必然相邻。因为其他数字至少出现大于1次,因此首尾如果与旁边不同则刚好是首尾,如果是在中间则需要比较是否与前后都不同才行,如此遍历一次即可。

class Solution {
public:
    int foundOnceNumber(vector<int>& arr, int k) {
         if(arr.size() == 0)
             return 0;
        sort(arr.begin(), arr.end()); //排序法
        //因为其他数字至少出现大于1次,因此首尾如果与旁边不同则刚好是首尾
        if(arr[0] != arr[1])
            return arr[0];  
        else if(arr[arr.size() - 1] != arr[arr.size() - 2])
            return arr[arr.size() - 1];
        for(int i = 1; i < arr.size() - 1; i++){
            if(arr[i] != arr[i - 1] && arr[i] != arr[i + 1]) //中间需要比较前后两个
                return arr[i];
        }
        return 0;
    }
};

复杂度分析:

  • 时间复杂度:,排序的复杂度为,遍历一次为
  • 空间复杂度:,无额外使用空间

方法二:哈希表
具体做法:
建立一个哈希表,key值表示数字,value值表示数字出现的次数,统计完数组中所有数字后,遍历哈希表,找到value为1的key值。

class Solution {
public:
    int foundOnceNumber(vector<int>& arr, int k) {
        map<int, int> mp;  //哈希表统计数字出现的次数
        for(int i = 0; i < arr.size(); i++){
            if(mp.find(arr[i]) != mp.end())
                mp[arr[i]]++;  //多次出现则增加
            else
                mp[arr[i]] = 1; //首次出现
        }
        for(auto iter = mp.begin(); iter != mp.end(); iter++){ //遍历哈希表找到出现一次的数字
            if(iter->second == 1)
                return iter->first;
        }
        return 0;
    }
};

复杂度分析:

  • 时间复杂度:,统计数字是,遍历哈希表是
  • 空间复杂度:,哈希表的大小,一共有种元素

方法三:位运算
具体做法:
我们用一个32个元素的数组来记录所有数字中二进制1的个数,因为其他每个数字出现k次,因此如果数组中没有只出现一次的数,全部都出现k次,我们可以发现,32位数组中单独每个元素模k都等于0,因为刚好都是k的倍数。如果加上只出现一次的数,那么模k就只剩下只出现一次的数的二进制中1的个数,再将其转换成十进制即可。
图片说明

class Solution {
public:
    int foundOnceNumber(vector<int>& arr, int k) {
        vector<int> dp(32, 0);  //保存所有数字二进制中1的个数
        int res = 0;
        for(int i = 0; i < arr.size(); i++){ 
            for(int j = 0; j < 32; j++){
                if((arr[i] >> j) & 1)
                    dp[j]++;
            }
        }
        for(int i = 0; i < 32; i++){
            if((dp[i] % k) & 1)  //模k还剩下1的
                res += 1 << i; 
        }
        return res;
    }
};

复杂度分析:

  • 时间复杂度:,遍历一次数组,再遍历一次32个的辅助数组
  • 空间复杂度:,辅助数组dp是常数空间