劍指offerr 56只出現一次的數字_系列(java)

只出現一次的數字系列

  • 異或的性質
  1. 兩個數字異或的結果a^b是將 a 和 b 的二進制每一位進行運算,得出的數字。 運算的邏輯是
  2. 如果同一位的數字相同則爲 0,不同則爲 1
  • 異或的規律
  1. 任何數和本身異或則爲 0

  2. 任何數和 0 異或是 本身

  3. 異或滿足交換律。 即 a ^ b ^ c ,等價於 a ^ c ^ b

136. 只出現一次的數字 1

給定一個非空整數數組,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。

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

面試題56 - I. 數組中數字出現的次數

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

###方法1 hashmap

  • 時間O(N)
  • 空間O(N)
//num1,num2分別爲長度爲1的數組。傳出參數
//將num1[0],num2[0]設置爲返回結
import java.util.HashMap;
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
        for(int i = 0; i < array.length; i++){
            if(map.containsKey(array[i])) map.put(array[i], 2);
            else map.put(array[i], 1);
        }
        int count = 0; //記錄num1是否被填充
        for(int i = 0; i < array.length; i++){
            if(map.get(array[i]) == 1){
                if(count == 0){
                    num1[0] = array[i];
                    count++;
                }else{
                    num2[0] = array[i];
                }
            }
        }
    }
}

方法2 位運算

  • 時間O(N)
  • 空間O(1)
//num1,num2分別爲長度爲1的數組。傳出參數
//將num1[0],num2[0]設置爲返回結果
import java.util.HashMap;
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        int sum =0; // 保存兩兩以獲得結果,其結果等於兩個只出現一次的元素的異或值。
        //將數組所有元素進行異或,最後的結果一定是那兩個單一數字的異或結果。看上圖示例
        //用示例[4,4,6,1]最後異或結果就是 6和1異或的結果 7

        for(int i = 0; i < array.length; i++){
            sum ^= array[i];
        }
        // 記錄第一次接獲結果其從低位到高位第一個爲1的首位。
        // 爲什麼要找它? 以爲兩個不一樣的值 其位運算第一次發生不一樣的時候,該位位運算結果就是1,找到該位置
        // 可以把整個數組劃分爲兩個部分。
        int first = 1;
        while((sum & first) == 0){ // 爲0進位,爲1不執行循環。
            first = first << 1;
        }
        
        //first爲1,所以我們可以根據數組元素的二進制低位第一位是否爲1,將數組分爲2類,
        // 示例數組可以分爲     低位第一位爲0:[4,4,6]     低位第一位爲1:[1]
        //此時再將兩個數組兩兩異或就可以得到最終結果。
        for(int i = 0; i < array.length; i++){
            // 將數組分類
            if((array[i] & first) == 0){
                num1[0] ^= array[i];
            }else{
                num2[0] ^= array[i];
            }
        }
    }
}

137. 只出現一次的數字 II

給定一個非空整數數組,除了某個元素只出現一次以外,其餘每個元素均出現了三次。找出那個只出現了一次的元素

class Solution {
    public int singleNumber(int[] nums) {
        int res = 0;
        // int型數據,最多隻有32位。
        for(int i = 0; i < 32; i++){
            int count = 0;
            int bit = 1 << i;
            for(int j = 0; j < nums.length; j++){
                // 如果三個相同的數在該位爲0,count不加
                // 如果三個相同的數在該位不爲0,count加,那麼,如果單獨的數與該位與後爲0,最後count一定是3的倍數。否則需要作與運算還原該位。
                if((bit & nums[j]) != 0){
                    count++;
                }
            }
            if((count % 3) != 0){
                res |= bit;
            }
        }
        return res;

    }
}
  • 牛客網,需要自定義輸入。類名統一用Main!
import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int [] nums = new int[n];
        for(int i = 0; i < n; i++){
            nums[i] = in.nextInt();
        }
        System.out.print(find(nums));
        in.close();
    }
    
    
    public static int find(int [] nums){
        int res = 0;
        // int型數據,最多隻有32位
        for(int i = 0; i < 32; i++){
            int count = 0;
            int bit = 1 << i;
            for(int j = 0; j < nums.length; j++){
                // 如果三個相同的數在該位爲0,count不加
                // 如果三個相同的數在該位不爲0,count加,那麼,如果單獨的數與該位與後爲0,最後count一定是3的倍數。否則需要作與運算還原該位。
                if((bit & nums[j]) != 0){
                    count++;
                }
            }
            if((count % 3) != 0){
                res |= bit;
            }
        }
        return res;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章