关于位运算的妙用

逻辑运算

1.如果想要实现:num * 2+ 1 则可以使用 (num>>)|1

2.实现两个数交换各自的值

public class Logic01 {
    public static void main(String[] args) {
        int a = 103;
        int b = 435;
        a = a ^ b;
        b = a ^ b;
        a = a ^ b;
        System.out.println(a);
        System.out.println(b);
    }
}

解析:(异或的特点:0 ^ 数 = 数; 数^数 = 0)

第一步: a = a ^ b;

第二步: b = a ^ b;//这里可以等价为:b = a ^ b ^ b = a;

第三步 :a = a ^ b;//这时等价:a = a ^ b = ( a ^ b ) ^ a = b ;

3.一个数组中有一个数出现了奇数次,其他都出现了偶数次,如何找到这个数并打印

public class Logic02 {
    public static void main(String[] args) {
        int[] arr = {1,1,1,1,2,2,2,3,3,4,5,5,4};
        int ero = 0;
        for (int i = 0; i < arr.length; i++) {
            ero ^= arr[i];
        }
        System.out.println(ero);
    }
}

在这里也可以包装成一个方法,可以增加代码复用性

解析:

该问题与上一题运用了同一技巧,因为其他数都为偶次出现,那么,出现了偶数次的数在异或期间,都等于了0,剩下那个出现奇数次的数与0异或得到的也就是这个数;

例如上面这个数组:四个一,三个二,两个三四五,数组中相互异或得到的自然就是这个数

4.一个二进制数,如何取出最右侧的那个一

用到了:int b = a & ( (~a) + 1)

例如:a = 0100110010100 ①

​ ~a = 1011001101011 ②

(~a) + 1= 1011001101100 ③

此时 ①&③ 得到的就是 0000000000100

        int a = 18;
        int b = a & ((~a) + 1);
        System.out.println(Integer.toBinaryString(b));//Inteage 中的方法,toBinaryString用于转换为二进制数

5.一个数组中两个数出现了奇数次,那么其他数出现了偶数次,如何找到并打印这两个数

此时比第三题难度增加很多,但是可以运用第三第四题,进行解决

思路:任然使用第3题的方法,这时ero = 第一个出现奇数次的数 ^ 第二个出现奇数次的数

因为这两个数必然不可能相等,所以此时利用第4题的方法,找到ero中最右侧的1,利用这个位置上的1,将原数组分为两类

一类为该位置上为1,另一类为0

继续使用异或,分别在这两类中进行异或,那么就得到了这两个数

如何利用这个数分类就显得尤为重要,假定这个数为a,a与这个数组中的每个数进行与,为0 ,就说明在此位置上相同,均为1,

public class Logic04 {
    public static void main(String[] args) {
        int[] arr = {1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 5, 4, 5};
        int ero = 0;
        for (int i = 0; i < arr.length; i++) {
            ero ^= arr[i];
        }
        int a = ero & ((~ero) + 1);
        int b = 0;
        for (int i = 0; i < arr.length; i++) {
            if ((arr[i] & a) != 0) {
                b ^= arr[i];
            }
        }
        System.out.println("一个出现奇数次的数为: " + b + "   另一个出现奇数次的数为: " + (ero ^ b));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值