手撕算法-位运算

位运算基础

位运算是把数字用二进制表示后,对每个位置上的0或者1 的运算
java中的位运算:

与(&)0&0=01&0=00&1=01&1=1
与(|)0|0=01| 0=10|1=11|1=1
异或(^)0^0=01^0=10^1=11&1=0

左移运算符(<<): m<<n表示把m左移n位。左移n位的时候,最左边的n位将会被丢弃,同时在最右边补上n个0;
如:
00001010<<2=00101000
10001010<<3=01010000

右移运算符(>>):m>>n表示右移n位。在c语言中如果是一个无符号数值,最右边的n位将会被舍弃,用0填补左边n位。如果是有符号数值最左边填充符号位。
但是值得注意的是,在java中没有无符号数值,因此右移(>>)左边都是填充符号位。同时java也有自己的无符号位移运算符(>>>),使用该运算符在最左边填充的是0.

题目汇总

二进制中1的个数

1、 二进制中的1的个数

题目描述:

请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

示例 1:

输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。

示例 2:

输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串00000000000000000000000010000000 中,共有一位为 ‘1’。

示例 3:

输入:11111111111111111111111111111101 输出:31
解释:输入的二进制串11111111111111111111111111111101 中,共有 31 位为 ‘1’。

解题思路:
将数值的每一位都与1 相与,按照位运算的性质 1&1=1,0&1=0,可以计算出二进制中1 的个数:

实现逻辑如下
在这里插入图片描述

代码实现:

public class Solution {
    public int hammingWeight(int n) {
        int cnt=0;
        while(n!=0){
            if((n&1)!=0){
                cnt++;
            }
            n=n>>1;
        }
        return cnt;
    }
}

当输入的是负数的时候,这种方式会出现问题,负数的符号位为1,每次右移左边都会填充1,最后的结果为0xFFFF,转换为整形为-1,会导致代码陷入死循环。参考下图:
在这里插入图片描述
解决方案:使用java中的无符号位移(>>>)

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int cnt=0;
        while(n!=0){
            if((n&1)!=0){
                cnt++;
            }
            n=n>>>1;
        }
        return cnt;
    }
}

算法改进 :
把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1 变为0.那么一个整数的二进制表示中有多少1,就可以做多少次这样的操作

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int cnt=0;
        while(n!=0){
            cnt++;
            n=(n-1)&n;
        }
        return cnt;
    }
}

整数变换

题目描述:
输入两个整数m和n,计算需要改变m的二进制中的多少位才能得到n。比如10的二进制表示为1010,13的二进制表示为1101,需要改变1010中的3位才能得到1101
这道题目是上面题目的变形,只需要先将两个数进行异或,然后统计异或或的值中二进制1的个数。
代码如下:

public static void main(String[] args) {
        int m=0;
        int n=1;
        
        int tmp=m^n;
        int cnt=0;
        while(tmp!=0){
            tmp=tmp&(tmp-1);
            cnt++;
        }
        System.out.println(cnt);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值