Single Number I & II

这周才发现原来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




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值