[LeetCode] 137. Single Number II (位操作)

传送门

Description

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

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

思路

题意:给定一个数组,其中有一个数出现一次,其他数出现三次,要求在时间复杂度为O(n)空间复杂度为O(1)的条件下,找出这个出现一次的数。

题解:

方法一:因为除了一个数外,其他每个数都出现三次,因此枚举每一位二进制位,统计每一位上这些数为1的数总共有多少个,然后与3相模,如果余1,证明这个出现一次的数的二进制在这位上为1。(此法是通用方法,适用于除一个数外,其他数出现k次,那么只需模k即可)

class Solution {
public:
    //12ms
    int singleNumber(vector<int>& nums) {
        int res = 0;
        for (int i = 0;i < 32;i++){
            int cnt = 0;
            int mask = 1 << i;
            for (int j = 0;j < nums.size();j++){
                if (nums[j] & mask){
                    cnt++;
                }
            }
            if (cnt % 3){
                res |= mask;
            }
        }
        return res;
    }
};

  

方法二:用两个变量记录所有数二进制位中哪些位为1出现一次,哪些二进制位为1出现两次,之所以只需两个,是因为同一个数最多只出现三次,因此我们可以选定状态 00 -> 01 -> 10来记录,那么我们用ones表示哪些位为1出现一次(模3后出现一次),用twos表示哪些位为1出现两次(模3后出现一次),当ones和twos某一二进制位上同时为1说明这位为1出现了三次,那么我们此时将ones和twos的这位二进制位清0,最后ones就是答案。

class Solution {
public:
    //9ms
    int singleNumber(vector<int>& nums) {
        int ones = 0,twos = 0,threes = 0;
        for (unsigned int i = 0;i < nums.size();i++){
            //以下两句代码不能颠倒次序,如若颠倒,则一个数先记录于ones,
            //然后twos的值依赖于ones及这个数,那么这个数就被统计了两次
            twos |= (nums[i] & ones);  //记录有哪些二进制位为1且出现两次存于twos
            ones ^= nums[i];           //记录有哪些二进制位为1且出现一次存于ones

            //以下三句是清零操作
            threes = ones & twos;
            ones &= ~threes;
            twos &= ~threes;
        }
        return ones;
    }
};

 

另外,方法二代码可精简如下:ones与twos的含义与上述相同。

class Solution {
public:
    //9ms
    int singleNumber(vector<int>& nums) {
        int ones = 0,twos = 0;
        for (unsigned int i = 0;i < nums.size();i++){
            //ones&~twos以及twos&~ones都是为了清零操作,两者二进制位都为1时清零
            ones = (ones ^ nums[i]) & (~twos);
            twos = (twos ^ nums[i]) & (~ones);
        }
        return ones;
    }
};

  

原文地址:https://www.cnblogs.com/ZhaoxiCheung/p/7397289.html