1. 程式人生 > >LeetCode260. 只出現一次的數字 III

LeetCode260. 只出現一次的數字 III

題目

給定一個整數陣列 nums,其中恰好有兩個元素只出現一次,其餘所有元素均出現兩次。 找出只出現一次的那兩個元素。

示例 :

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

注意:

  1. 結果輸出的順序並不重要,對於上面的例子, [5, 3] 也是正確答案。
  2. 你的演算法應該具有線性時間複雜度。你能否僅使用常數空間複雜度來實現?

分析

方法呢是從網上看來的,自己理解了半天,然後把自己的理解過程寫下來,寫的有些囉嗦,表達能力差,描述的也不清楚,自己多理解理解,應該也差不多了 ,但這是我最近幾天來寫的最認真的一次解題報告了,嘻嘻嘻。 好, 接下來就是我囉裡囉嗦的解題思路了     :)

1. 陣列中所有數字做異或運算,因為有兩個元素只出現一次,所以最後的異或運算結果sum 為兩個單獨元素x,y的異或結果。因為相同數字異或運算結果為0。

我們要得到x,y的結果,就是要利用sum把x,y分出來。

2. 我們把陣列nums分為兩組,其中x在一組,y在另一組。那麼按照什麼來分組呢?

我們知道陣列所有元素異或運算(也就是x,y的異或運算)sum的結果一定不為0,因為x≠y,那麼x和y的二進位制表示中肯定有一或多位不相等,即肯定存在x中的某一位值為 1 , y中相同位的值為 0 。我們依據x和y中某一位值不一樣將陣列分為兩組:

分組一包含x,也就是某特定位為1(0)的所有元素,分組二包含y,也就是某特定位為0(1)的所有元素。

3. 那麼接下來,怎樣按照上述方法去判斷陣列中某位的值是0是1呢?

可以用與&運算。我們引入一個flag值,flag表示的是x,y的二進位制表示中,值不同的一位,將這一位取值為1,其它所有位取值為0(如果還存在其它取值不同的位,也置為0)。這裡我們確定flag值的方法 :  flag = sum & (~(sum - 1));

舉個例子,比如 x = 5,y = 3: 

首先轉換二進位制 x = 101 y = 11     ——>    異或運算  sum = x ^ y = 110    ——>    flag取值 flag = 10 (010)

4. 好找到了flag然後可以用與&運算了,x,y中肯定有一個數字同flag做與&運算時取值為0。為啥,因為flag為0的位,無論同1還是0做與運算都位0,那麼flag為1的位只有一位,而這位是根據x,y不同位確定的位數,也就是說x,y同flag為1位相同的位數,一個是0,另一個是1,是0的那個數做與運算當然結果為0了。 其它數也根據是根據這個道理,進行了分組。

5. 最後將分組一內所有的元素做異或運算,得出x,將分組二內所有元素做異或運算,得出y。為啥,因為啊分組一(二)中的數,除去x和y以外,都是相同的數字啦,相同的數字做異或,得0呀。

下面是程式碼啦

程式碼

class Solution {
    public int[] singleNumber(int[] nums) {
        int[] re = new int[2];
        int sum = nums[0];
        
        for (int i = 1; i < nums.length; i++)
            sum ^= nums[i];

        int flag = sum & (~(sum - 1));

        for (int i = 0; i < nums.length; i++) 
            if ((nums[i] & flag) == 0) re[0] ^= nums[i];
            else re[1] ^= nums[i];
            
        return re;
    }
}