数据结构与算法基础总结------3.异或运算

本文介绍了异或运算的基本性质及其在算法中的实际应用,包括如何使用异或运算无额外变量交换两个数,找出数组中出现奇数次的数,提取整数最右侧的1,以及在数组中有两种数出现奇数次时如何找到这两种数。通过实例解析,展示了异或运算是如何简化问题并提供高效解决方案的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、认识异或运算

        异或运算是算法中非常简单的一种运算,原理其实就是进行位运算,是一种无进位相加,基本所有对异或运算的应用都可以总结为异或运算的俩个性质,异或运算的性质:

1.0^N = N  ; N^N = 0。

2.异或运算满足交换律和结合

二、实例解析

    1.如何不用额外变量交换两个数

    public static void test03(int num1, int num2){
        //必须保证指向的内存是相同的
        num1 = num1 ^ num2;
        num2 = num1 ^ num2;// = num1 ^ num2 ^ num2 = num1 ^ 0 = num1;
        num1 = num1 ^ num2;// = num1 ^ num2 ^ num1 = num2 ^ 0 = num2;
        System.out.println(num1);
        System.out.println(num2);
    }

    2.一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数 

    /**
     * @Author zhangchunming
     * @Description //TODO 一个数值中有一个数出现奇数次,其他数出现偶数次,如何找出它
     * @Date 23:44 2021/4/28
     * @Param [arr1]
     * @return int
     **/
    public static int test01(int[] arr1){
        //循环异或,最终留下的就是奇数
        int ero=0;
        for(int i=0;i<arr1.length;i++){
            ero=ero^arr1[i];
        }
        return ero;
    }

    3.怎么把一个int类型的数,提取出最右侧的1来(就是将值转换为二进制,查看最右侧的1)

        思路:这个思路在后边的题中经常使用。取反加一之后的值,除了最右侧的1,其他相反状态

    /**
     * @Author zhangchunming
     * @Description //TODO 如何把一个整形的数,提取出最右侧的1(二进制中)
     * @Date 22:49 2021/5/7
     * @Param [num]
     * @return int
     **/
    public static int test02(int num){
        //取反加一之后的值,除了最右侧的1,其他相反状态
        int num1=~num+1;
        System.out.println(num1);//101
        return num1 & num;
    }

    4.一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数

        思路:在数组中a、b出现奇数次,那么将数组整体进行异或操作得出eor=a^b,找到eor中最左位置的1,假设此位置为rightOne,说明在此位置时a、b的值不相等,因为如果相等的话异或为0,此时可以将数组分为俩类,在rightOne这个位置上,一类数为0,一类数为1,这俩类分别包含a和b。此时只需要异或其中一类就可以,就可以找到a,之后将a和eor进行异或得到b(满足交换律)。

    /**
     * @Author zhangchunming
     * @Description //TODO 一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数
     * @Date 17:35 2021/8/18
     **/
    public static void printOddTimesNum2(int[] arr) {
        int eor = 0;
        // eor = a ^ b
        for (int i = 0; i < arr.length; i++) {
            eor ^= arr[i];
        }
        // 提取出最右的1
        // 这个值类似于:0000 0000 0010,只有一个1其他都为0
        int rightOne = eor & (~eor + 1); 
        int onlyOne = 0; // eor'
        for (int i = 0 ; i < arr.length;i++) {
            //举例:arr[1] = 1111 1111 1101
            //   rightOne = 0000 0000 0010
            //   运算结果:   0000 0000 0000 = 0
            //  下边也可以写为  if ((arr[i] & rightOne) != rightOne) {
            if ((arr[i] & rightOne) != 0) {
                //将所有在rightOne 位置为0的值进行异或,得到其中一个奇数贼
                onlyOne ^= arr[i];
            }
        }
        System.out.println(onlyOne + " " + (eor ^ onlyOne));
    }

     

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

!春明!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值