leetcode136-137:single number

shuaishuai3409發表於2016-04-28

LC136:Given an array of integers, every element appears twice except for one. Find that single one.
LC137:
Given an array of integers, every element appears three times except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
LC136和LC137這兩個題很像,前者是一整數陣列中,僅有一個元素出現一次,其餘均出現兩次,後者是僅有一個元素出現一次,其餘均出現三次,都要求找到僅出現一次的那個元素。而且要求都線上性時間O(n)以及不要建立額外的陣列實現。

思路:
如果可以使用額外的空間,我們可以建立一個陣列filter,通過遍歷一次原始陣列,儲存所有不相同元素出現次數,然後在遍歷一次filter,就可以找到出現一次的元素,這樣的時間複雜度為O(3n)。甚至我們可以把原始陣列的資料放到hashmap中去,直接就可以統計出不同元素出現的次數,但如果看過hashmap原始碼的同學,就會知道時間複雜度就不是O(n)了,而是O(log)級別的。其實對於這種找元素出現次數的問題,我們可以採用位運算實現。


LC136:

位運算有4種:與&、或|、非~、異或^,而且位運算通常針對二進位制運算子。對於異或我們應該記住以下公式:
a^b=b^a
a^b^c=a^(b^c)=a^(c^b)
a^a=0
0^a=a
a^a^b^b^c^d^c=d
相同元素異或為0,擴充套件為偶數個相同元素異或為0; 0和任何元素異或為任何元素。

對於LC136:陣列所有元素取異或,出現兩次的元素異或後為0,那麼最終異或結果就是隻出現一次的元素。測試通過程式碼如下:

public class Solution {
    public int singleNumber(int[] nums) {
        int result=nums[0];
        for(int i=1;i<nums.length;i++){
            result=(result^nums[i]);
    }
        return result;
}
}

LC137:
這題相對麻煩些,對於出現奇數次+1次的,不能直接用異或來實現。這裡可以結合 的概念。
1與任何元素與運算都是任何元素;0與任何元素或運算都是任何元素。
除一個元素出現一次外,其餘元素均出現三次。這裡也有幾個共識需要大家掌握:

  • 十進位制運算可以轉換為二進位制運算
    以3+5+6=14為例,我們把每個十進位制數轉換為二進位制數進行相加運算,最終的偽二進位制為222,轉換為十進位制為2+2
    *
    21
    ^1
    +2
    *
    22
    ^2
    =14,恰恰等於以十進位制方式相加的結果。
    0 1 1
    1 0 1
    1 1 0
    ————
    2 2 2

將每個元素考慮為一個32位的二進位制數,這樣每一位上出現要麼為1 ,要麼為0。統計陣列每一位上1 出現的次數count,必定是3N或者3N+1 次。讓count對3取模,能夠獲得到那個只出現1次的元素該位是0還是1。

程式碼:
public class Solution {
    public int singleNumber(int[] nums) {
        int length = nums.length;  
        int result = 0;  
        for(int i = 0; i<32; i++){  
            int count = 0;   
            int temp = 1<< i;  
            for(int j=0; j<length; j++){  
                if((nums[j] & temp[)!=0)  
                    count++;  
            }  
          if(count %3==1)  
                result |= temp;  
        }  
        return result;  
    }
}

附上java進位制轉換:java中進行二進位制,八進位制,十六進位制,十進位制間進行相互轉換

十進位制轉成十六進位制:
Integer.toHexString(int i)
十進位制轉成八進位制
Integer.toOctalString(int i)
十進位制轉成二進位制
Integer.toBinaryString(int i)
十六進位制轉成十進位制
Integer.valueOf(“FFFF”,16).toString()
八進位制轉成十進位制
Integer.valueOf(“876”,8).toString()
二進位制轉十進位制
Integer.valueOf(“0101”,2).toString()

相關文章