【位运算简单例题】

位运算

在这里插入图片描述

位运算的一些规则

  • a^b,a和b相同结果为0,不同为1

  • 异或可以实现两个数的交换,前提就是这两个数在内存中是分开存储的,因为交换过程中a和b对应的内存数据一直在变化。

  • 0和任何数异或结果都是这个数本身

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

例子

已知一个数组中只有一种数出现了奇数次,其他所有数都出现了偶数次,怎么找到这个出现了奇数次的数?

已知一个数组中有两种数出现了奇数次,其他所有数都出现了偶数次,怎么找到这两个出现了奇数次的数?

要求时间O(N),空间O(1)

第一问:很简单,声明一个变量eor,初始为0,遍历数组都异或一边,最终的结果就是这个值

第二问:和上一问一样先异或一遍,结果eor = a^b,由于a!=b,所以eor必然有一位上为1,下面就是找到一个1,之后

解题

思路笔记都在代码注释里面了 😄

public class EvenTimesOddTimes {

    /**
     * 第一问:很简单,声明一个变量eor,初始为0,
     * 遍历数组都异或一边,最终的结果就是这个值
     */
    public static void getEvenTimesNum(int[] arr){
        int eor = 0;
        for (int i = 0; i < arr.length; i++) {
            eor ^= arr[i];
        }
        System.out.println(eor);
    }

    public static void getTwoEvenTimeNums(int[] arr){
        int eor = 0;
        for (int num : arr) {
            eor ^= num;
        }
        /** 循环结束,假设那两个数为a和b,那么eor = a^b;
         *
         * a和b不相等,那么他们肯定有一个位上的数不同,
         * 就代表着eor上必然有一位的数字为1
         * 下面来找到这个1
         *
         * eor最右侧的1,提取出来
         * eor :     00110010110111000
         * ~eor:     11001101001000111
         * ~eor+1:   11001101001001000
         *
         * 就是补码,所以直接取-eor = ~eor+1
         * eor和 - eor进行与运算,得到最后侧的1
         * eor :     00110010110111000
         * -eor:     11001101001001000
         * &运算:    000000000000001000
         */
        // rightOne :00000000000001000
//		int rightOne = eor &( ~eor +1);//取反加一,相当于-eor
        int rightOne = eor & (-eor); // 提取出最右的1

        /**
         * 找到这个位置上的1之后,那么数组中的数就可以分为两类,一类是这个位置上为0的,一个是为1的
         * 这样a和b肯定不会分到同一类中,所以就可以拆分成了第一问那种情况
         */

        int aOrb = 0;
        for (int i = 0; i < arr.length; i++) {
            if((arr[i]&rightOne) == 0){//即,这个位置上不是1
                //得出的结果不是a就是b
                aOrb ^= arr[i];
            }
        }
        System.out.println(aOrb+","+(aOrb^eor));
    }



    public static void main(String[] args) {
        int[] arr = {2,3,4,5,3,4,5};
        getEvenTimesNum(arr);//2
        int[] arr1 = {2,3,4,5,3,4,5,5};
        getTwoEvenTimeNums(arr1);//2,5
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值