zoukankan      html  css  js  c++  java
  • 【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 求余,结果则为只出现一次的数字。

    Picture1.png

    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;
        }
    }
    
  • 相关阅读:
    OpenGL ES学习001---绘制三角形
    Mac关机时处于黑屏状态
    静态变量和实例变量的区别(配图解释专业术语,通俗易懂)
    用shape画内圆外方,形成一个圆形头像
    最全的敏捷认证对比(CSM/PMI-ACP/EXIN)
    Certified Scrum Master CSM 中文资料大全
    如何打造优秀的远程敏捷团队(9步)
    博客搬家
    权威的国际敏捷认证Certified Scrum Master (CSM)
    博客园入驻了
  • 原文地址:https://www.cnblogs.com/XDU-Lakers/p/14158787.html
Copyright © 2011-2022 走看看