【LeetCode】137. 只出現一次的數字 II(劍指offer 56-II)

137. 只出現一次的數字 II(劍指offer 56-II)

知識點:哈希表;位運算java

題目描述

給你一個整數數組 nums ,除某個元素僅出現 一次 外,其他每一個元素都恰出現 三次 。請你找出並返回那個只出現了一次的元素。算法

你的算法應該具備線性時間複雜度。 你能夠不使用額外空間來實現嗎?數組

示例
輸入:nums = [2,2,3,2]
輸出:3

輸入:nums = [0,1,0,1,0,1,99]
輸出:99

解法一:HashMap

和136題同樣,使用哈希表存儲每一個數字出現的數字,再遍歷哈希表,看誰能等於1;
很容易想到,但這樣作的壞處就是須要開闢新的空間;code

class Solution {
    public int singleNumber(int[] nums) {
        Map<Integer,Integer> map = new HashMap<>();
        for(Integer i : nums){
            map.put(i, map.getOrDefault(i, 0)+1);
        }
        for(Integer i: map.keySet()){
            if(map.get(i) == 1) return i;
        }
        return -1;
    }
}

時間複雜度:O(N);
空間複雜度:O(N);get

解法二:位運算

這題不能再用異或去解了,由於變成了三個沒有辦法抵消,可是想象一下,若是有三個如出一轍的數字,那這三個數字二進制相加後,全部位上要麼是0;要麼全是3的倍數;而後咱們的多餘元素,要麼加上去爲0;要麼加上去多了一個1,因此能夠依次求每位的和,而後%3,若是值爲1,那證實咱們在這位上的值爲1;不然爲0;
以下圖所示;hash

image

class Solution {
    public int singleNumber(int[] nums) {
        //在java中int類型是32位,咱們須要統計全部數字在某一位置的和能不能被3整除,
        // 若是不能被3整除,說明那個只出現一次的數字的二進制在那個位置是1……把32位所有統計完爲止
        int ans = 0;
        for(int i = 0; i < 32; i++){
            int count = 0; //統計1的個數;
            for(int j = 0; j < nums.length; j++){
                count += (nums[j] >> i) & 1; //統計全部數在第i位上1的個數;
            }
            if(count % 3 != 0){
                ans = ans | (1 << i); //其餘位不變,第i位置爲1;
            }
        }
        return ans;
    }
}

時間複雜度:O(N);
空間複雜度:O(1);io

體會

**掌握位運算的解決方法:這種題目每每要按位與、按位異或等操做;
此外還會有左移<<;右移>>等;好比說:class

a & 1 : a的其餘位全爲0,最後一位不變:即取a最後一位;
a | (1 << i) : a的其餘位不變,把a的第i位置爲1;
(a >> i) & 1 : 取出a第i位上的值;hashmap

相關文章
相關標籤/搜索