1. 程式人生 > 實用技巧 >【LeetCode】三題解決常見異或運算題

【LeetCode】三題解決常見異或運算題

題目一

1.1 題目連結

136. 只出現一次的數字

1.2 題目描述

1.3 解題思路

1.位運算之異或操作

異或的性質如下
(1) 兩個數字異或的結果:a ^ b = 將 a 和 b 的二進位制每一位進行運算,得出的數字.
(2) 運算的邏輯是:如果同一位的數字相同則為 0,不同則為 1
(3) 任何數和本身異或則為0,6 ^ 6 = 0
(4) 任何數和0異或是本身, 6 ^ 0 = 6
(5) 異或滿足交換律。 即 a ^ b ^ c ,等價於 a ^ c ^ b

1.4 AC程式碼

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

題目二

2.1 題目連結

劍指 Offer 56 - I. 陣列中數字出現的次數

2.2 題目描述

2.3 解題思路

1.依舊是利用異或運算

異或的性質如下
(1) 兩個數字異或的結果:a ^ b = 將 a 和 b 的二進位制每一位進行運算,得出的數字.
(2) 運算的邏輯是:如果同一位的數字相同則為 0,不同則為 1
(3) 任何數和本身異或則為0,6 ^ 6 = 0
(4) 任何數和0異或是本身, 6 ^ 0 = 6
(5) 異或滿足交換律。 即 a ^ b ^ c ,等價於 a ^ c ^ b

與題目一相比,本題難度在於得把兩個不同的數字分開,分到兩個組中,然後在兩個組中分別利用題目一的解法即可求出答案。

核心思路:兩個不同的數字的二進位制表達中至少有一位不同,根據這一位不同結合&運算的結果即可把兩個數字分開,因為其餘數字都是兩兩相同,所以相同的數字必然是分到同一組中。我們只需要找出那位不同的數字mask,即可完成分組( & mask )操作。

num1:       101110
num2:       111110
num1^num2:  010000

可行的mask:  010000 

num1&mask = 000000
num2&mask = 010000
這樣就成功把兩個不同的數字分為兩組,

2.4 AC程式碼

class Solution {
    public int[] singleNumbers(int[] nums) {
        int mask = 0;
        int[] ans = new int[2];
        int ans1 = 0;
        int ans2 = 0;
        for(int i = 0; i < nums.length; i++){
            mask = mask ^ nums[i];
        }
        int bit = 0;
        while(true){
            int a = mask & 1;
            if(a == 1){
                mask = (int)Math.pow(2,bit);
                break;
            }
            mask = mask >> 1;
            bit++;
        }
        for(int i = 0; i < nums.length; i++){
            int a = nums[i] & mask;
            if(a == 0){
                ans1 = ans1 ^ nums[i];
            }else{
                ans2 = ans2 ^ nums[i];
            }
        }
        ans[0] = ans1;
        ans[1] = ans2;
        return ans;
    }
}

題目三

3.1 題目連結

劍指 Offer 56 - II. 陣列中數字出現的次數 II

3.2 題目描述

3.3 解題思路

這一題就不能單純的利用異或運算解決問題了。

考慮數字的二進位制形式,對於出現三次的數字,各 二進位制位 出現的次數都是 33 的倍數。因此,統計所有數字的各二進位制位中 11 的出現次數,並對 33 求餘,結果則為只出現一次的數字。

3.4 AC程式碼

class Solution {
    public int singleNumber(int[] nums) {
        int sum[] = new int[32];
        for(int i : nums){
            int tot = 0;
            int temp = 1;
            while(tot < 32){
                int num = i & temp;
                if(num != 0) sum[tot] += 1;
                temp <<= 1;
                tot++;
            }
        }
        int ans = 0;
        for(int i = 0; i < 32; i++){
            if(sum[i] % 3 == 0){
                sum[i] = 0;
            }else{
                sum[i] = 1;
                ans += (int)Math.pow(2,i);
            }
        }
        return ans;
    }
}