运用位运算解题

位运算符

在处理整形数值时,可以直接对组成整形数值得各个位进行操作。

位运算有:

&   与   两个位都为1时,结果才为1
|   或  两个位都为0时,结果才为0
^  异或  两个位相同为0,相异为1
~  取反  0变1,1变0

>>和<<运算符将二进制位进行右移或者左移操作

使用位运算判断数的奇偶性

要知道奇数最后一位二进制为 1,偶数最后一位二进制为 0

public static boolean isOdd(int i){
        //与运算
        return (i&1)!=0;
    }

位运算交换两个整数变量的值

异或,可以理解为不进位加法:1+1=0,0+0=0;1+0=1

异或运算性质 x ^ x ^ y == y,因为x ^ x == 0,0 ^ y == y

public static void main(String[] args){
    int a = 10;
    int b = 20;
    a = a ^ b;
    b = b ^ a;
    a = a ^ b;
    System.out.println(a + "\t" + b);
}

使用位运算,不用判断语句,求整数的绝对值

对一个数进行位运算,是在这个数的补码上运行的 。正数的补码是原码,负负数的补码是对其原码逐位取反,但符号位除外,然后整个数加1。

因为给定数是负数,则符号位为“1”。取反加一 。

例如:-7的原码(10000111)→按位取反(11111000)(负数符号位不变)→加1 。所以-7的补码是11111001。

 int 型,先右移31位取符号位 如果a位正数,i=0;a为负数,i=-1 。

一个数与-1即与0xFFFFFFFF异或就相当与取反 。因此,a与i异或后再减i(因为i为0或-1,所以减i即是要么加0要么加1)也可以得到绝对值

public static int abs(int a){
    int i = a >> 31;
    return ((a ^ i) -i);
}

位运算判断一个数转为二进制后的第i位数是0还是1

因为0和1做与运算结果还是0,1和1做与运算结果才是1。

所以,我们可以把1的二进制中的1左移(i-1)位再与目标数做与运算,这样目标数转为二进制后的第i位如果是1结果为1,如果是0结果为0。

public static void main(String[] args){
    int x = 85;
    System.out.println("x的第五位二进制位的数为:" + ((((x & (1 << 4)) >> 4) == 1) ? "1" : "0"));
    // 比如85的二进制为1010101,我们将它的二进制与1向左移4位来做与运算
    // 就是 1010101 & 0010000  得出结果0010000 再右移4位 即可得出结果
}

查找数组中唯一成对的数

这里也可以利用异或运算的性质,两个相同的数异或结果为0,可以用来消除重复

 1-n这n个数放在含有n+1个元素的数组中,只有唯一的一个元素重复,其他均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出,不用辅助存储空间,能否设计一个算法实现。

异或运算可以用来消除重复,但是此题需要查找重复的数。所以可以先将重复的数看为一个1~n内的随机数,并放在数组末端。然后,用0和数组内1~n-1个数进行异或再与原来数组异或,这样就会有n-1个重复两次的数和一个重复三次的数。最终重复两次的数会被消除,最终留下的就是所求答案。

这个题目给出了数组范围所以可以用位运算解题,但是如果题目中没有告诉该数组的范围就只能用辅助存储空间这个方法 。

public class Main{
    public static void main(String[] args){
        //先用较小的数构造,便于验证
        int N = 11;
        int[] arr = new int[N];
        for (int i = 0; i < arr.length - 1; i++) {
            arr[i] = i + 1;
        }
        //最后一个数是随机数
        arr[arr.length - 1] = new Random().nextInt(N - 1) + 1;//nextInt()会随机生成一个整数,这个整数的范围就是int类型的范围-2^31 ~ 2^31-1,但是如果在nextInt()括号中加入一个整数a那么,这个随机生成的随机数范围就变成[0,a)。
        //随机下标
        int index = new Random().nextInt(N);
        swap(arr, index, arr.length - 1);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + "  ");
        }
        System.out.println();
        int x1 = 0;
        for (int i = 1; i <= N - 1; i++) {
            x1 = (x1 ^ i);   // 求得1到N-1这些连续的数的异或
        }
        for (int i = 0; i < N; i++) {
            x1 = (x1 ^ arr[i]);  // 再与原来的数组arr异或,这样重复的数就有三个,不重复的数有两个,异或消除重复后,剩下的就是重复的数了
        }
        System.out.println(x1);
        System.out.println("使用辅助空间实现============");//如果题目中没有告诉该数组的范围就只能用此方法
        int[] helper = new int[N];
        for (int i = 0; i < helper.length; i++) {
            helper[arr[i]]++;
        }
        for (int i = 0; i < helper.length; i++) {
            if (helper[i] == 2) {
                System.out.println(i);
                break;
            }
        }
    }
    public static void swap(int[] arr,int x,int y){
        int temp = arr[x];
        arr[x] = arr[y];
        arr[y] = temp;
    }
}

二进制中1的个数

  10100(N)
-1
 ————————
  10011(N-1) => (N-1)&N=10000
  重复操作 得00000
  故此操作进行的次数就是二进制中1的个数
import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int K=sc.nextInt();
        System.out.println(Integer.toString(K,2));//先看一下输入的数的二进制形式
        int count01=0;
        while (K != 0) {
            K=(K&(K-1));
            count01++;
        }
        System.out.println(count01);
    }
}

用一条语句判断一个整数是不是2的整数次方

2的整数次方转换为二进制有一个特点,只有一个1。可以把问题转化为,该数二进制中是否只有一个1。

public class Main{
    public static void main(String[] args){
        int Z=sc.nextInt();
        System.out.println(Integer.toString(Z,2));//先看一下输入的数的二进制形式
        int count02=0;
        if ((Z&(Z-1))==0) {
            System.out.println("该数是2的整数次方");
        }
    }
}

二进制小数——判断一0~1之间的小数的二进制形式

给定一个介于0和1之间的实数,(如:0.625),类型为double,打印它的二进制表示(0.101,因为小数点后的二进制分别表示0.5,0.25,0.125....)。

如果该数字无法精确地用32位以内的二进制表示,则打印“ERROR”

小数点后的1分别表示0.5,0.25,0.125(0.1=>0.5;0.101=>0.625)

小数变二进制——乘2,小数点前有1就在对应位置写1,没有则为0
 eg:0.625                  

                                                二进制
   第一次:    0.625*2=1.25           0.1
   第二次:(1.25-1)*2=0.5       0.10
   第三次:       0.5*2=1              0.101

如果程序对附加字符串的需求很频繁,不建议使用+来进行字符串的串联。
可以考虑使用java.lang.StringBuilder 类,使用这个类所产生的对象默认会有16个字符的长度,也可以自行指定初始长度。
如果附加的字符超出可容纳的长度,则StringBuilder 对象会自动增加长度以容纳被附加的字符。

public class Main{
    public static void main(String[] args) {
        double num=0.3;
        StringBuilder sb=new StringBuilder("0.");
        //小数变二进制——乘2,小数点前有1就在对应位置写1,没有则为0
        while (num>0){
            //乘2,挪整
            double r=num*2;
            //判断整数部分
            if (r>=1){
                sb.append("1");//append( )是往动态字符串数组添加,相当于“xxxx”+“yyyy”中的‘+’号
                //消掉整数部分
                num=r-1;
            }else{
                sb.append("0");
                num=r;
            }
            if (sb.length()>34){//若该数字无法用32位以内的二进制表示,输出“ERROR”
                System.out.println("ERROR");
                return;
            }
        }
        System.out.println(sb.toString());
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值