Java 每日一道算法题(^(异或))

这篇博客介绍了如何利用异或操作的特性解决两种情况下的问题:1) 数组中有一个数字出现奇数次,其余次数均出现偶数次;2) 数组中有两个数字出现奇数次,其余次数均出现偶数次。通过异或所有数组元素,可以找到这两个问题的答案。此外,还展示了如何用异或操作交换两个数值,以及给出了相应的代码实现。
摘要由CSDN通过智能技术生成

问题1:

        数组中有一个数字出现奇数次,其余次数均出现偶数次,找到这个出现奇数次的数字

问题2:

        数组中有两个数字出现奇数次,其余次数均出现偶数次,找到这个出现奇数次的数字

解题思路

利用 ^(异或:可以理解为无进位相加)的特性

   a        0 0 0 0 1 1 0 0

   b        1 1 0 0 1 0 1 0

a ^ b      1 1 0 0 0 1 1 0

特性 1)、

           N ^ 0 = N

           N ^ N = 0

特性 2)、

        满足交换律或结合律

        a ^ b ^ c = a ^ (b ^ c)、 a ^ b = b ^ a

特性 3) 、

        异或顺序与结果无关(参考特性2)

代码实现:

    public static void main(String[] args) {
        // 数组中有一个数字出现奇数次,其余次数均出现偶数次,找到这个出现奇数次的数字
        int arrs[] = {2, 2, 2, 2, 3, 3, 3, 5, 5, 6, 6, 2, 2, 1, 1};
        int eor = 0;
        for (int arr : arrs) {
            eor ^= arr;
        }
        System.out.println(eor);
    }
    public static void main(String[] args) {
        // 数组中有两个数字出现奇数次,其余次数均出现偶数次,找到这个出现奇数次的数字
        int arrs[] = {2,2,2,2,3,3,3,5,5,5,6,6,2,2,1,1};
        int eor = 0;
        for(int arr: arrs){
            eor ^= arr;
        }
        // eor = a ^ b
        System.out.println(eor);

        // 获取a ^ b的最右为1的位置(将a、b区分在两个区间内,因为a与b的)
        /**
         * a = 00000011 = 3
         * b = 00000101 = 5
         * 从右侧开始找到不同数的位置,根据这个位置将数组arrs分为两个阵营,
         * 找到数组中与该位置相同的数 进行异或操作,那么最后剩下的就是 a、b其中一个
         * 将a、b 与 eor 继续异或就可以获得另一个数据
         */
        int right = eor & (~eor + 1);
        System.out.println(right);

        int a = 0;
        for(int arr: arrs){
            if((right & arr) == 0){
            // if((right & arr) > 0){
                a ^= arr;
            }
        }
        System.out.println("a: " + a);
        System.out.println("b: " + (eor ^ a));
    }

延伸

两个数值型数据交换位置(经常用于数组中数据交换,但是注意数组中的 i、j不能相同(内存地址指向不同),否则会变成0

    public static void main(String[] args) {
        int s1 = 10;
        int s2 = 20;
        
        s1 = s1 ^ s2;
        s2 = s1 ^ s2; // s1 ^ s2 ^ s2 - > s1
        s1 = s1 ^ s2; // s1 ^ s2 ^ s1 - > s2
        System.out.println("s1: " + s1);
        System.out.println("s2: " + s2);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值