题意:给定一个数组,已知这个数组中有一个数出现了一次,其它数都出现三次。找出这个数
解法:
有个很好理解的解法,因为int有32位,所以开一个数组bit[32],遍历32次,把每个位出现的次数分别存入数组中,最后bit[32]分别对3取模,得到的结果,只出现一次的数。
这个算法的时间复杂度为O(32*N),相当的高。
从别的地方you看到另一种解法,复杂度为O(N),乍一看看不懂,遂好好分析了一下:
class Solution {
public:
int singleNumber(int A[], int n)
int one,two,three;
one=two=three=0;
for(int i=0;i<n;i++)
{//一定是出现3次,2次,1次这样的顺序,如果反过来的话,先更新了one的话,会影响到two和three的
three = two & A[i];//已经出现了两次,还出现了一次
two = two | one & A[i];//出现了1次又出现了1次,在加上以前已经出现了2次的,为新的出现了2次的
one = one | A[i];//出现了1次
//将出现3次的其出现1次2次全部抹去
one = one & ~three;
two = two & ~three;
}
return one;
}
};
代码是随便找的,大概思想就是,int占32位,于是用三个变量one,two,three,分别表示出现一次,出现两次,出现三次的 位 ,我们最后只要出现一次的,也就是one的值,就是数组中只出现一次的数。
那么,如何用one,two,three分别存储出现一次两次三次的位呢?
首先,one中存的是出现一次的,所以one&A[i]即得到这次出现两次的位(&代表one和A[i]都有,所以必然是出现了两次)
即two = one&A[i];
同理three = two&A[i];
但是这里要强调一下,three=two&A[i]是没错,但是,这是这次出现过的位
所以程序有几个步骤
1,计算出,这次出现三次的位
2,计算出,one|(这次出现一次的位),two|(这次出现两次的位)
3,剔除one中出现两次的位,two中出现三次的位。