位运算基础
位运算是把数字用二进制表示后,对每个位置上的0或者1 的运算
java中的位运算:
与(&) | 0&0=0 | 1&0=0 | 0&1=0 | 1&1=1 |
---|---|---|---|---|
与(|) | 0|0=0 | 1| 0=1 | 0|1=1 | 1|1=1 |
异或(^) | 0^0=0 | 1^0=1 | 0^1=1 | 1&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);
}