一個整型數組里除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字


一、題目:

  一個整型數組里除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。例如數組為{1,3,5,7,1,3,5,9},找出7和9。

二、解答:

1、運用異或運算符的解法

   我們先考慮上述問題的簡單版本:   一個數組里面只有一個數字出現一次,其他都出現兩次,請找出這個數字。

        這個問題可以可以使用用異或的性質解決。異或的性質:對於整數a,有

                         (1) a^a=0

                         (2)a^0=a

                         (2)a^b^c=a^(b^c)=(a^c)^b

      利用以上的性質,上面的題目的解法為:

public static void findNumAppearOnce(int[] arr) {
        int result = 0;
        for (int i = 0; i < arr.length; i++) {
            result ^= arr[i];
        }
        System.out.println(result);
View Code

    有了以上的基礎,解文章開始時提出的問題的思路如下:

  (1)對於出現兩次的元素,使用“異或”操作后結果肯定為0,那么我們就可以遍歷一遍數組,對所有元素使用異或操作,那么得到的結果就是兩個出現一次的元素的異或結果。

  (2)因為這兩個元素不相等,所以異或的結果肯定不是0,也就是可以再異或的結果中找到1位不為0的位,例如異或結果的最后一位不為0。

  (3)這樣我們就可以最后一位將原數組元素分為兩組,一組該位全為1,另一組該位全為0。

  (4)再次遍歷原數組,最后一位為0的一起異或,最后一位為1的一起異或,兩組異或的結果分別對應着兩個結果。

 /*
 解法1:
1、思路:
(1)對於出現兩次的元素,使用“異或”操作后結果肯定為0,那么我們就可以遍歷一遍數組,對所有元素使用異或操作,那么得到的結果就是兩個出現一次的元素的異或結果。
(2)因為這兩個元素不相等,所以異或的結果肯定不是0,也就是可以再異或的結果中找到1位不為0的位,例如異或結果的最后一位不為0。
(3)這樣我們就可以最后一位將原數組元素分為兩組,一組該位全為1,另一組該位全為0。
(4)再次遍歷原數組,最后一位為0的一起異或,最后一位為1的一起異或,兩組異或的結果分別對應着兩個結果。
2、復雜度:
  (1)時間復雜度:第一次循環,將所有元素異或得到對應結果,時間開銷為O(n);第二次循環,找出第一次異或結果為1的位,時間開銷為O(32);第三次循環,根據為1的位將元素分為兩組進行異或得到兩個結果,時間復雜度為O(n),所以總的時間復雜度為T(n) = 2*O(n)+O(32) = O(n)。
  (2)空間復雜度:常數,因為只分配了兩個空間用於結果的保存,因此空間復雜度為常數。
 */

    public static int[] findNumsAppearOnce2(int[] arr) {
        if(arr.length < 2)
            return arr;

        int[] result = new int[2];  //要返回的結果  
        int res = arr[0];  //第一次對所有元素進行亦或操作結果  
        for(int i=1; i<arr.length; i++) {
            res ^= arr[i];
        }
        int bitIndex = 0;
        for(int i=0; i<32; i++) {  //找出亦或結果為1的位。  
            if((res>>i & 1) == 1) {
                bitIndex = i;
                break;
            }
        }
        for(int i=0; i<arr.length; i++) { //根據bitIndex為1,將元素分為兩組  
            if((arr[i] >> bitIndex & 1) == 1)
                result[0] ^= arr[i];   //對應位為1,亦或得到的結果  
            else
                result[1] ^= arr[i];   //對應位為0,亦或得到的結果  
        }

        return result;
    }
View Code

2、運用HashMap的解法

(1)思路:

  使用一個Map,Map對應的鍵值key就是數組中的元素,value就是這個元素出現的次數。這樣我通過一次遍歷數組中的元素,
如果元素出現在map中,則將其對應的value加1,否則將元素添加到map中,這樣遍歷一遍數組,我們就可以得到數組中每個元素對應出現的次數,
然后再通過遍歷一遍map,返回value為1對應的key就是我們需要求得元素。

 /*
解法2:
(1)思路:這個可以可以使用一個Map,Map對應的鍵值key就是數組中的元素,value就是這個元素出現的次數。這樣我
通過一次遍歷數組中的元素,如果元素出現在map中,則將其對應的value加1,否則將元素添加到map中,這樣遍歷一遍數組,我們就可以得到數組中每個元素對應出現的次數,然后再通過遍歷一遍map,返回value為1對應的key就是我們需要求得元素。
(2)時間復雜度:因為首先需要遍歷一遍數組,時間開銷為O(n),構建完map后需要遍歷一遍map找到value為1的元素,而map的個數為n/2,時間開銷為O(n/2),所以總的時間開銷為O(n)。
(3)空間復雜度:因為需要建立一個map,而且最后map的大小為n/2,所以空間復雜度為O(n)。
*/
    public static void findNumsAppearOnce1(int[] arr) {
        //Map對應的鍵值key就是數組中的元素,value就是這個元素出現的次數
        Map<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
        for (int i : arr) {
            if (hashMap.containsKey(i)) {
                hashMap.put(i, hashMap.get(i) + 1); //如果存在,value值加1
            } else {
                hashMap.put(i, 1); //如果不存在,存入hashMap,value值等於1
            }
        }

        //遍歷一遍map,返回value為1對應的key就是我們需要求得元素
        Set<Integer> set = hashMap.keySet();
        for (int i : set) {
            if (hashMap.get(i) == 1) {
                System.out.print(i+" ");
            }
        }
    }
View Code

 

參考鏈接:http://blog.csdn.net/yangfeisc/article/details/45314703

 

 
        

     

 

     


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM