1. 程式人生 > >LeetCode-137:Single Number II (只出現一次的數字)

LeetCode-137:Single Number II (只出現一次的數字)

題目:

Given a non-empty 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?

例子:

Example 1:

Input: [2,2,3,2]
Output
: 3

Example 2:

Input: [0,1,0,1,0,1,99]
Output: 99

問題解析:

給定一個非空整數陣列,除了其中一個元素外,其餘每個元素均出現三次。找出這個只出現一次的元素。

連結:

思路標籤

位運算狀態機

解答:

  • 和LeetCode 136:Single Number屬於類似的問題,136中給出其他元素均出現兩次,我們使用“異或”運算,即:0^a=aa^a=0,即可求得結果;
  • 但是當元素上升到3個及3個以上時,就無法繼續使用這麼簡單的方法來實現了,下面給出三種實現方法,其中後面的兩種是相同的,同時第一種和最後一種方法對於任意一個重複K次的相似問題均是通用的。

1. 統計每一位1的個數,和對3取餘

  • 對每個整數以32位表示,分別統計每一位上1的個數,最後該位數上的和對3取餘數;
  • 如果餘數不為0,則說明該位上只出現一次的元素,在該位上有1;
  • 通過移位操作和1做位與運算,則可求得當前元素在該位是否有1。
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret = 0;
        for(int i=0; i<32; ++i){
            int sum = 0;
            for
(int j=0; j<nums.size(); ++j){ sum += (nums[j]>>i) & 1; } ret |= (sum % 3)<<i; } return ret; } };

2. 狀態機法,用2個數分別表示狀態機的3個狀態

  • 利用狀態機表示:我們用下面的三種狀態來表示對於某個數字出現了多少次:00、01、10、00,也就是我們累加的過程0——>1——>2——>0,當滿3個數字時則記為0次。
  • 所以,我們可以用兩個整數(32位)來表示所有數中每一位上出現1的次數。例子:ones的第3位為1,twos的第3位為0,則表示當前累計的所有元素中,各個元素的第3位上出現1的個數為2個。
  • 寫出對應關係:
    • 00 (+) 1 = 01
    • 01 (+) 1 = 10
    • 10 (+) 1 = 00 ( mod 3)
  • 那麼我們用ab來表示開始的狀態,對於加1操作後,得到的新狀態的ba(其中a表示倒數第一位,b表示倒數第2位)的演算法如下:
    • a = a xor r & ~b;
    • b = b xor r & ~a;
  • 因為我們最後要求的是隻出現1次的元素,所以通過對所有元素的位運算後,32個位上出現1只有一次的元素就是我們要返回的元素,也就是ones當前儲存的元素。
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ones = 0, twos = 0;
        for(int i=0; i<nums.size(); ++i){
            ones = (ones^nums[i]) & ~twos;
            twos = (twos^nums[i]) & ~ones;
        }
        return ones;
    }
};

3. 狀態機法,用K-1個數分別表示狀態機的K個狀態(通法)

  • 下面的解法是與解法2同樣思想的解法,但其可以解決任意K個重複元素的問題。
  • 同時,對於不同的K,假設只有一個元素重複3次,其餘重複K次,K>3,那麼我們還可以用下面的方法返回bits[2]來得到該返回元素,具體就不展開分析。
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        return singleNumber(nums, 3);
    }

    int singleNumber(vector<int>& nums, int _K) {
        int K = _K - 1;
        int bits[K] = {0};
        for (int num : nums) {
            for (int i = 0; i < K; i++) {
                int mask = -1;
                for (int j = 0; j < K; j++) if (j != i)
                    mask &= ~bits[j];
                bits[i] = (bits[i] ^ num) & mask;
            }
        }
        return bits[0];
    }
};