根据经验,要求O(n)复杂度的算法多要用到hashmap,所以naive的版本一代码如下,平均需要n/3的额外存储空间
class Solution {
public:
int singleNumber(int A[], int n) {
if(n==0)
{
return -1;
}
map<int,int> mmap;
for(int i=0;i<n;++i)
{
if(mmap.count(A[i]))
{
mmap[A[i]]++;
}
else
{
mmap[A[i]]=1;
}
}
for(map<int,int>::iterator itr=mmap.begin();itr!=mmap.end();++itr)
{
if(itr->second==1)
{
return itr->first;
}
}
return -1;
}
};
本题最优的解法是采用位操作,无奈对位操作还是不熟练,参看论坛大神代码如下:
https://oj.leetcode.com/discuss/6632/challenge-me-thx
public int singleNumber(int[] A) {
int ones = 0, twos = 0;
for(int i = 0; i < A.length; i++){
ones = (ones ^ A[i]) & ~twos;
twos = (twos ^ A[i]) & ~ones;
}
return ones;
}
https://oj.leetcode.com/discuss/857/constant-space-solution
int singleNumber(int A[], int n) {
int count[32] = {0};
int result = 0;
for (int i = 0; i < 32; i++) {
for (int j = 0; j < n; j++) {
if ((A[j] >> i) & 1) {
count[i]++;
}
}
result |= ((count[i] % 3) << i);
}
return result;
}
理解这个题以后,就可以推而广之,解决一系列类似这样的问题:“一组数中每个不同的数都出现a次,但有一个数不同,它出现b(b<a)次,求这个数”。
我们开一个数组 int k[ a],用k[i]来代表一个数,这个数中的每一位都出现过i次(即在n个数中,有一个数出现了i次,这样对这n个数做一个统计,就可以得到只有这个数满足每一位都出现过i次,k[i]就是这个数)
接下来就是遍历一遍原数组来填充和更新数组k中的值,每次从原数组拿到一个数,都要完整更新一次k数组,因为k数组记录的是不同出现次数的数,所以每次得到一个新的数都要完整更新k数组,有人会问那么如果有两个不同的数x,y,它们在原数组中都出现过c次,那么在k数组中k[ c ]代表的究竟是x还是y,答案是既不代表x,也不代表y。这也就是k数组只能复原出出现次数唯一的数。
int singleNumber(int A[],int n,int k, int l){
int t;
int* x = new int[k]();
x[0] = ~0;
for (int i = 0; i < n; i++) {
t = x[k-1];
for (int j = k-1; j > 0; j--) {
x[j] = (x[j-1] & A[i]) | (x[j] & ~A[i]);
}
x[0] = (t & A[i]) | (x[0] & ~A[i]);
}
<span style="white-space:pre"> </span>return x[l];
}
我理解的还是不太透彻,问题中的限制只能有一个“异类”,这个限制要如何突破暂不清楚,用上述代码做了测试,只能在满足只有一个“异类的情况下成功”。