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


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

知識點:哈希表;位運算

題目描述

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

你的算法應該具有線性時間復雜度。 你可以不使用額外空間來實現嗎?

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

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

解法一:HashMap

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

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);

解法二:位運算

這題不能再用異或去解了,因為變成了三個沒有辦法抵消,但是想象一下,如果有三個一模一樣的數字,那這三個數字二進制相加后,所有位上要么是0;要么全是3的倍數;然后我們的多余元素,要么加上去為0;要么加上去多了一個1,所以可以依次求每位的和,然后%3,如果值為1,那證明我們在這位上的值為1;否則為0;
如下圖所示;

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);

體會

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

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


免責聲明!

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



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