异或操作在编程题中的应用

目录

一、异或操作介绍

1、异或操作的运算规则

2、异或操作的基本运算原则

3、异或操作的应用

二、编程题示例

1、Leetcode 136:只出现一次的数字

2、Leetcode 137:只出现一次的数字Ⅱ

3、Leetcode 260:只出现一次的数字Ⅲ

4、Leetccode 268:丢失的数字

一、异或操作介绍

1、异或操作的运算规则

相同为0,不同为1。

2、异或操作的基本运算原则

  • 0与任何数进行异或,结果都是任何数。
  • 任何数与任何数异或,结果为0。
  • 异或运算满足交换律和结合律

3、异或操作的应用

(1)用于两数交换。

 注意:用于异或操作的两个数,必须指向不同的地址空间。如果指向同一块地址,则异或操作的结果为0。

(2)用于查找数组中只出现一次的数或缺失的数。

二、编程题示例

1、Leetcode 136:只出现一次的数字

题目描述:

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,1]

输出: 1

示例 2:

输入: [4,1,2,1,2]

输出: 4

思路:

根据异或运算的规则,对两个相同数字做异或运算,其结果为0。根据题目描述,数组中的元素只有一个数字出现了一次,其余数字都出现了两次。这样的话通过异或操作正好可以排除掉成对的数字,而最终所得结果即为出现一次的数字。

代码:

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

2、Leetcode 137:只出现一次的数字Ⅱ

题目描述:

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

示例 1:

输入:nums = [2,2,3,2]

输出:3

示例 2:

输入:nums = [0,1,0,1,0,1,99]

输出:99

思路:

对本题进行分析,可以发现与上一题很相似,但是通过单一的异或操作无法成功找到出现一次的数字。就数组而言,仅有一个元素出现一次,其余数字出现了三次。

对于数组中的任一元素,其十进制都对应一个32位的二进制数。数组中的元素除取出现一次的数字外,都是三个为一组的。因此可以将数组元素对应的二进制数的对应位进行求和,然后将每一个对应位的和进行模3运算,得到的余数即为出现一次的数组元素所对应的值。

代码:

class Solution {
    public int singleNumber(int[] nums) {
        int result = 0;
        for(int i=0; i < 32; i++){
            //对每一位对应的二进制进行求和
            int sum = 0;
            //移位,判断数组中的每一位
            int t = 1 << i;
            for(int j=0; j< nums.length; j++){
                if((nums[j] & t) != 0){
                    sum++;
                }
            }
            //如果不能被3整除,则说明一个数的那个数的第i位不是0
            if(sum % 3 != 0){
                result |= t;
            }
        }
        return result;
    }
}

3、Leetcode 260:只出现一次的数字Ⅲ

题目描述:

给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。

进阶:你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?

示例 1:

输入:nums = [1,2,1,3,2,5]

输出:[3,5]

解释:[5, 3] 也是有效的答案。

示例 2:

输入:nums = [-1,0]

输出:[-1,0]

示例 3:

输入:nums = [0,1]

输出:[1,0]

思路:

1、定义一个变量,遍历数组并进行异或操作。

2、遍历结束即为这两个只出现一次的数字异或的结果。

3、提取出最右边的1,再次遍历数组。即可找到其中一个数。

4、再次异或即可得到两个出现一次的数字。

 代码:

class Solution {
    public int[] singleNumber(int[] nums) {
        int result = 0;
        // 异或运算,找到两个出现一次的数字的异或结果
        for(int i=0; i < nums.length; i++){
            result ^= nums[i];
        }
        // 找到最右边的1
        int rightOne = result & (~result + 1);
        // 其中一个出现一次的数字
        int singleNum1 = 0;
        for(int i=0; i < nums.length; i++){
            if((nums[i] & rightOne) == 0){
                singleNum1 ^= nums[i];
            }
        }
        // 得到两个出现一次的数字
        singleNum1 = result ^ singleNum1;
        int singleNum2 = result ^ singleNum1;
        // 返回结果
        int[] ret = {singleNum1, singleNum2};
        return ret;
    }
}

4、Leetccode 268:丢失的数字

题目描述:

给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。

示例 1:

输入:nums = [3,0,1]

输出:2

解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。

示例 2:

输入:nums = [0,1]

输出:2

解释:n = 2,因为有 2 个数字,所以所有的数字都在范围 [0,2] 内。2 是丢失的数字,因为它没有出现在 nums 中。

示例 3:

输入:nums = [9,6,4,2,3,5,7,0,1]

输出:8

解释:n = 9,因为有 9 个数字,所以所有的数字都在范围 [0,9] 内。8 是丢失的数字,因为它没有出现在 nums 中。

示例 4:

输入:nums = [0]

输出:1

解释:n = 1,因为有 1 个数字,所以所有的数字都在范围 [0,1] 内。1 是丢失的数字,因为它没有出现在 nums 中。

思路:

和前面几道题很类似,还是使用异或运算。

代码:

class Solution {
    public int missingNumber(int[] nums) {
        int result = 0;
        int n = nums.length;
        for(int i=0; i <= n; i++){
            if(i == n){
                result ^= i;
            }else{
                result ^= nums[i] ^ i;
            }
        }
        return result;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值