Single Number II -- leetcode

来源:互联网 发布:头颅移植 知乎 编辑:程序博客网 时间:2024/06/06 04:05

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

0 0
原创粉丝点击