异或运算及相关面试题

本文探讨了异或运算在编程中的应用,如交换变量、寻找数组中奇数次出现的数、提取右most 1和识别两种奇数次数元素。通过实例展示了如何利用异或操作解决实际问题,同时介绍了时间复杂度和空间复杂度优化的方法。
摘要由CSDN通过智能技术生成

异或定理

  • 异或:相同为0,不同为1.也就是无进位相加。
    • 0 ^ N = N
    • N ^ N = 0
    • (a ^ b) ^ c = a ^ (b ^ c)

相关面试题

  • 1.如何不用额外变量交换两个数
  • 2.一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数
  • 3.怎么把一个int类型的数,提取出来最右侧的1
    • 结果:a & (-a) ,也就是 a & (~a + 1),因为 -a = ~a + 1.
  • 4.一个数组中,有两种数出现了奇数次,其他数都出现了偶数次,怎么找到,并打印这两种数
  • 5.一个数组中,有一种数出现了K次,其他数都出现了M次,M > 1,K < M ,找到出现了K次的数。要求:额外空间复杂度O(1),时间复杂度O(N)。

题①

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

    /**
     * 如何不用额外变量交换两个数
     * 前提是这两个数的内存位置不同,否则异或操作的结果为0
     * @param a
     * @param b
     */
    public static void swap2Num(int a,int b){
        a = a^b;
        b = a^b;
        a = a^b;
    }

题②

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

    /**
     * 一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数
     */
    public static int findNum(int[] arr){
        int temp = arr[0];
        for (int i = 1; i < arr.length; i++) {
            temp ^= arr[i];
        }
        System.out.println(temp);
        return temp;
    }

题③

怎么把一个int类型的数,提取出来最右侧的1

    /**
     * 怎么把一个int类型的数,提取出来最右侧的1
     */
    public static int getRightOne(int num){
        return num & (-num);
    }

题④

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

   /**
     * 一个数组中,有两种数出现了奇数次,其他数都出现了偶数次,怎么找到,并打印这两种数
     */
    public static int[] find2Members(int[] arr){
        if(arr == null || arr.length < 2){
            return new int[]{};
        }
        int eor = 0;
        for(int n:arr){
            eor ^= n;
        }
        //eor = a ^ b;
        //找到eor最右侧的1
        int rightOne = eor & (-eor);
        int b = 0;
        for (int i = 0; i < arr.length; i++) {
            if((rightOne & arr[i]) != 0){
                //说明arr[i]元素在最右侧的1同样位为1
                b ^= arr[i];
            }
        }
        int a = eor ^ b;
        int[] rs = {a,b};
        CommonUtils.printArray(rs);
        return rs;
    }

题⑤

一个数组中,有一种数出现了K次,其他数都出现了M次,M > 1,K < M ,找到出现了K次的数。要求:额外空间复杂度O(1),时间复杂度O(N)

  • 分析:
    - 所有的数的二进制位相加的数组,是32个元素的int数组
    - int数组的每个元素如果是M的倍数,说明出现K次的这种数在这个位上是0,不是1
    - int数组的每个元素如果不是M的倍数,说明出现K次的这种数在这个位上是1,不是0
public static int findKNum(int[] arr,int k,int m){
        //所有的数的二进制位相加的数组
        int[] bitArr = new int[32];
        for (int num : arr){
            for (int i = 0; i < 32; i++) {
                //数组arr每个元素第i位上的值的累加和
                bitArr[i] += (num >> i) & 1;
            }
        }
        //出现k次的数
        int kNum = 0;
        for (int i = 0; i < 32; i++) {
            if(bitArr[i] % m != 0){
                //说明出现k次的数,在i位上是1.则需要kNum上在i位填充1。也就是如下
                kNum |= 1 << i;
            }
        }
        System.out.println(kNum);
        return kNum;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值