找出陣列中只出現一次的數字

網際網路資深架構師發表於2020-12-13

給定一個非空整數陣列,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。

說明:

你的演算法應該具有線性時間複雜度。 你可以不使用額外空間來實現嗎?

示例 1:

輸入: [2,2,1]
輸出: 1

示例 2:

輸入: [4,1,2,1,2]
輸出: 4

如果沒有時間複雜度和空間複雜度的限制,可以使用集合儲存數字。遍歷陣列中的每個數字,如果集合中沒有該數字,則將該數字加入集合,如果集合中已經有該數字,則將該數字從集合中刪除,最後剩下的數字就是隻出現一次的數字。
Java程式碼如下:

 public int singleNumber(int[] nums) {
        Set<Integer> set = new HashSet< Integer>();
        for (int i = 0; i < nums.length; i++) {
            if (set.contains(nums[i])){
                //已經存在,從集合中刪除
                set.remove(nums[i]);
            }
            else set.add(nums[i]);
        }
        return set.iterator().next();
    }

上述解法需要額外使用 O(n)的空間,其中 n 是陣列長度。如果要求使用線性時間複雜度和常數空間複雜度,上述解法顯然不滿足要求。那麼,如何才能做到線性時間複雜度和常數空間複雜度呢?

答案是使用位運算。對於這道題,可使用異或運算 ⊕。異或運算有以下三個性質。

任何數和 0 做異或運算,結果仍然是原來的數,即 a⊕0=a。
任何數和其自身做異或運算,結果是 0,即 a⊕a=0。
異或運算滿足交換律和結合律,即 a⊕b⊕a=b⊕a⊕a=b⊕(a⊕a)=b⊕0=b。

因此,陣列中的全部元素的異或運算結果即為陣列中只出現一次的數字。

Java程式碼如下:

public int singleNumber(int[] nums) {
        int single = 0;
        for (int i:nums)
            single ^= i;
        return single;
    }

複雜度分析

時間複雜度:O(n),其中 nnn 是陣列長度。只需要對陣列遍歷一次。

空間複雜度:O(1)。

相關文章