260. 只出現一次的數字 III

中等 位運算 數組

思路

  1. 出現奇數次的數字有兩個(a,ba, b),所以將所有數字亦或之後的結果會是 aba\oplus{b}
  2. aba\neq{b},所以 ab0a\oplus{b}\neq0

根據第二點,兩個數字間,一定至少有一位元是不相等的。
而不相等的位置,就是有 11 的位置。
在那之前,先去找到 aba\oplus{b} 最右邊的 11 所在的位置。

要想到一個數字 nn 最右的 11,能透過位運算做到。
nn 的二進制是:xxxx1000
nn 反向之後:yyyy0111
反向之後再加 1,相當於取相反數 n\mathbin{\sim}{n}
加一的操作不會影響到左邊的反向結果 yy
然後將 nnn\oplus{-n},就得到最右邊的數字 1 所在的位置了。

yyyy011100000001+yyyy1000\begin{array}{} \text{yyyy0111} & \\\text{00000001} & + \\\hline\text{yyyy1000} \end{array} xxxx1000yyyy100000001000\begin{array}{} \text{xxxx1000} & \\\text{yyyy1000} & \oplus \\\hline\text{00001000} \end{array}

abxxxx100(ab)yyyy100&0000100\begin{array}{} a\oplus{b} & \text{xxxx}10\dots0 & \\-(a\oplus{b}) & \text{yyyy}10\dots0 & \& \\\hline&000010\dots0 \end{array}

假設不同的位置在第 pos\text{pos} 位,我們能將數字分成以下兩堆,並分別做亦或操作。

  • pos\text{pos} 位為 11 的數字。
  • pos\text{pos} 位為 00 的數字。

因為相等的數字會被消掉,兩堆最後剩下的數字,各自就會是 aabb

程式碼

位運算

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        long long xor_all = 0;
        for(int num : nums) {
            xor_all ^= num;
        }
        int diff = xor_all & ~(xor_all - 1); // 避免 -xor_all 溢出導致 diff 出問題
        int a = 0, b = 0;
        for(int num : nums) {
            if(num & diff) a ^= num; // num & diff 只會是 diff or 0
            else b ^= num;
        }
        return {a, b};
    }
};

複雜度分析

  • 時間複雜度:O(n)O(n)
  • 空間複雜度:O(1)O(1)

顯示設定

背景線條
顯示背景網格線條
懸停發光
滑鼠懸停時顯示霓虹效果
聚光燈
跟隨滑鼠的聚光燈效果
背景透明度
開啟透明玻璃效果
主題顏色
自訂主要顏色