这周才发现原来leetcode有不少题喜欢连着两道(第一道简单,第二道进阶)。上周用了个简单粗暴的遍历方法实现了Single Number II,当时对位运算的方法不屑(现在才发现自己错了,算法的魅力真的很大),今天用一种异或的方法做了I之后发现这要比原来的无脑遍历计数方法要好太多了。
(1) Single Number I:
class Solution {
public:
int singleNumber(int A[], int n) {
if(n==1)
return A[0];
int x=A[0];
for(int i=1;i<n;i++)
x=x^A[i];
return x;
}
};
位运算真是个奇妙的东西,满足交换律和结合律的性质很适合无序数组的reduce运算。
(2) Single Number II:
class Solution {
public:
int singleNumber(int A[], int n) {
int tmp[32],a,result=0;
for(int i=0;i<32;i++)
tmp[i]=0;
for(int k=0;k<n;k++)
for(int i=0;i<32;i++)
{
a=(A[k]>>i)&1;
tmp[i]+=a;
}
for(int i=0;i<32;i++)
{
tmp[i]%=3;
result+=tmp[i]<<i;
}
return result;
}
};
因为相同出现的次数是3次,如果把所有数对应每一位都加起来模3,次数出现三次的数模3都余0,剩下的就是那个只出现过一次的数,进一步可以把3扩展到n次,如果n是偶数就是(1)的解决方法或者模2,如果n是奇数就把所有数对应每一位都加起来模n[1]。算法实现起来只需要用到相应的位运算(移位,与)。这算法跟无脑遍历计数方法比较起来时间快了足足一半(50ms vs 100ms)。
还有一种貌似看到的最短的代码,原理也是基于模3[2],但是代码实现的方式还看不太懂(用了比较高技巧的位运算导致代码太简洁可读性很差)。
参考:
[1] http://www.cnblogs.com/changchengxiao/p/3413294.html
[2] http://oj.leetcode.com/discuss/857/constant-space-solution