1. 程式人生 > >[LeetCode] 137. Single Number II (位運算)

[LeetCode] 137. Single Number II (位運算)

清零 一次 .com blog 適用於 soft hat ever rip

傳送門

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;
    }
};

  

[LeetCode] 137. Single Number II (位運算)