[LeetCode] 137--Single Number II --Medium--

说实话,看到这道题的答案的时候还是很震惊的。。。

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?

Hide Tags Bit Manipulation
Hide Similar Problems (M) Single Number (M) Single Number III

原题链接:https://leetcode.com/problems/single-number-ii/
与其类似的题目:[LeetCode] 136–Single Number –Medium–

大概意思是:给出一个整型数组,只有一个数字只出现了一次,其他数字出现了3次,找出没有重复的那一个数字。
要求,1时间效率是线性的;2能否实现不利用额外存储空间?

这道题小弟确实连答案都看了好久。。。看看下面两种优雅的解答方法:

解法一:因为数组中数字出现的规律:要么是一次,要么是三次;这样可以累加(int 为32位)32位二进制中每一位(二进制)出现1的次数,这32个数的累计值分别是能被3整除,或者是余1这两种可能。

public int singleNumber(int[] nums) {  
    int[] digits = new int[32];  
    for(int i=0;i<32;i++)  
    {  
        for(int j=0;j<nums.length;j++)  
        {  
            // 累加每一位二进制上值位“1”的值 >>i 且&1是为了取到 第i位上的二进制的值
            digits[i] += (nums[j]>>i)&1;  
        }  
    }  
    int res = 0;  
    for(int i=0;i<32;i++)  
    { 
        res += (digits[i]%3)<<i;  
    } 
    return res;  
}

解法二:运用了精密的位运算。。。
分析:对于除出现一次之外的所有的整数,其二进制表示中每一位1出现的次数是3的整数倍,将所有这些1清零,剩下的就是最终的数。用ones记录到当前计算的变量为止,二进制1出现“1次”(mod 3 之后的 1)的数位。用twos记录到当前计算的变量为止,二进制1出现“2次”(mod 3 之后的 2)的数位。当ones和twos中的某一位同时为1时表示二进制1出现3次,此时需要清零。即用二进制模拟三进制计算。最终ones记录的是最终结果。

int singleNumber(int A[], int n) {
    int ones = 0, twos = 0, threes = 0;
    for (int i = 0; i < n; i++) {
        twos |= ones & A[i];
        ones ^= A[i];
        threes = ones & twos;
        ones &= ~threes;
        twos &= ~threes;
    }
    return ones;
}

没看懂的朋友,可以点击查看下面的方法二参考链接,还是我拷贝过来把,省的以后链接没了就麻烦。

只看这几行代码,很难得其要领,如很多人的转载。原文解释如下:

ones as a bitmask to represent the ith bit had appeared once.
twos as a bitmask to represent the ith bit had appeared twice.
threes as a bitmask to represent the ith bit had appeared three times.
When the ith bit had appeared for the third time, clear the ith bit of both ones and twos to 0. The final answer will be the value of ones.

three计算完之后,要清零ones和twos,这和二进制加法相同。可能还有人觉得难以理解,尤其是第一句:
twos |= ones & A[i]; // ones代表1出现一次的位元,如果A[i]对应位是1则&后为1代表出现两次了,否则为0;结果就是twos中为1的位,表示该位出现两次1
第二句:

ones ^= A[i]; // 出现偶数则为0,出现奇数则为1,本题没有出现偶数的情况,所有ones代表出现1,3,5,……等位;但后面的语句会将其它情况去掉
第三句:

threes = ones & twos;// 相当与三进制加法。
第四、五句:

ones &= ~threes;  //加完之后要清理,如果three为1则ones和twos对应位清0;如果为0,则ones twos和1相与保持不变。
twos &= ~threes;  //这两句处理第二句中Ones其它奇数次情况,即ones如果为大于1的奇数,则此处必然被清0

方法一参考:http://blog.csdn.net/linhuanmars/article/details/22645599
方法二参考:http://m.blog.csdn.net/blog/ylzintsinghua/41924385
http://www.cnblogs.com/daijinqiao/p/3352893.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值