码迷,mamicode.com
首页 > 其他好文 > 详细

Single Number II -- leetcode

时间:2015-05-31 12:31:13      阅读:118      评论:0      收藏:0      [点我收藏+]

标签:位运算   leetcode   

Given an array of integers, every element appears three times except for one. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?


算法一,

每个数都出现3次,只有一个数出现1次。

以二进制的眼光来看,统计数的每个bit位为1的个数。如果每个数都出现3次的话,则每位1出现的总次数一定为3的整倍数。

设立32个计数器,统计整数每个位上1出现的总次数。再对3取余。结果则为只出现1次的整数的对应bit位的值。

在leetcode上实际执行时间为20ms。


class Solution {
public:
    int singleNumber(vector<int>& nums) {
        const int BITS = sizeof(int) * 8;
        vector<int> counts(BITS);
        for (auto num: nums) {
            for (int i=0; i<BITS; i++)
                if (num & 1 << i)
                    counts[i]++;
        }
        
        int ans = 0;
        for (int i=0; i<BITS; i++) {
            if (counts[i] % 3)
                ans |= 1 << i;
        }
        return ans;
    }
};

不过由于题目要求不使用额外的辅助空间,且提示用位运算,故此代码不是特别满足题目要求。但提供了一种好的思路。



算法二,位运算

思路同上,但是采用位运算。

算法一是统计完1出现的总次数,然后对3取余。

可以改进为,在累加过程,将累加和进行即时对3作取余操作。即到3后,就自动溢出。

那么只需要3种状态, 即0,1,2。   

如果用二进制来表示3状态的话,只需要2个bit位。则三状态为:00,01,10。

一个整数提供32个计数器,每个计数器为1位。

则采用2个整数,提供32个计数器,每个为2位。   其中一个计数器的权重为1(下面代码的变量one),另一个计数器的权重为2(下面代码变量two).

剩下要解决的是,如何作累加统计;以及如何溢出。

累加  可以用 异或, 还有逻辑与,两种运算代替。

简单的说,异或运算,就是不带进位的加法。  而 进位,则用 逻辑与 来处理。

对应下面代码来讲,两数加相加结果存入one中,如果有进位,将对应位存入变量two中。


然后要解决的问题,就是溢出问题(或者说对3取余)。 即到3了。自动回到0.

变量threee,就求出了,那些值已经为11的计数器。three的如果一个位为1,则表示对应的计数器已经为3. 则需要置该计数器为0.


此代码在leetcode上实际执行时间为12ms。


class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int two = 0, one = 0;
        for (auto num: nums) {
            two ^= one & num;
            one ^= num;
            
            const int three = two & one;
            two &= ~three;
            one &= ~three;
        }
        
        return one;
    }
};


算法三

上面位运算还有种更简化的写法。不过比上面的要难懂一些。

但是基本思路一样。都是围绕  00, 01, 10, 这三种状态转换作文章。即每种状态在加1时,如何转到下一个状态。

1. 当高位为0时,低位可以作加法运算(异或)。 此时,可从 00, 转换成 01; 01 转换成 00.

对于后者, 由于产生了进位, 还需要处理进位。此时高位需再进行一次加法运算。 

2. 当高位为1时,低位必为0.  此时,对着高位加进法。  完成从  10 转变成 00.

 

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://leetcode.com/discuss/6632/challenge-me-thx

Single Number II -- leetcode

标签:位运算   leetcode   

原文地址:http://blog.csdn.net/elton_xiao/article/details/46286661

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!