只出現一次的數字問題

問題1

給定一整形數組,已知該數組中一個數出現了一次,其餘的數出現了偶數次,找到這個出現一次的數

解法一:使用hashMap記錄次數,然後返回只出現一次的那個數

代碼如下:

    public int singleNumber(int[] nums) {
        Map<Integer, Integer> map = new HashMap<>();
        for(int num : nums) {
            int val = map.containsKey(num) ? map.get(num) + 1 : 1;
            map.put(num, val);
        }
        for(int num : nums) {
            if(map.get(num) == 1) {
                return num;
            }
        }
        return 0;
    }

時間複雜度爲O(N),額外空間複雜度O(N)

解法二:使用位運算。我們知道兩個相同的數進行異或操作後的結果是0,任何數和0異或的結果是它本身,異或操作亦具有交換律。因此我們只需讓數組中所有數異或到一起,結果即爲所求。

代碼如下:

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

時間複雜度O(N),額外空間複雜度O(1)。

問題2

給定一整型數組,已知其存在兩個數出現了一次,其它數出現了偶數次,找到那連個出現一次的數。

該問題依然可以使用HashMap進行求解,解法與問題一相同,不加贅述了。

該問題中由於含有兩個出現一次的數,如直接全部異或的到的結果爲這兩數的異或,因此無法直接按問題一解法求解。

一個想法是將這兩個數分開,分別求解,我們知道若兩數相同則其在任一位都相同,若兩數不同,則總是存在一位不同的位。由於我們已經得到了這兩數的異或記做XOR1,找到XOR1中爲1的那一位,可得該位上這兩數一定不同,因此可以通過該位是否爲1可以將數組分爲兩塊,分別對這兩塊求異或即爲所求。

實現代碼如下:

    public int[] singleNumber(int[] nums) {
        int xor1 = 0;
        for(int num : nums){
            xor1 ^= num;
        }
        int number = 0; // 存儲爲1的位數
        for(int i = 0; i < 32; i++){
            if((xor1 & 1) == 1){
                number = i;
                break;
            }
            xor1 = xor1 >> 1;
        }
        int val1 = 0, val2 = 0;
        for(int num : nums){
            if(((num >> number) & 1) == 1){
                val1 ^= num;
            }else{
                val2 ^= num;
            }
        }
        return new int[] {val1, val2};
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章