一、负数的补码表示
计算机中的负数均已补码的形式出现,优势是进行负数运算时可以直接使用加法器进行运算
原码:5= 00000101
-5= 10000101 首位变为1
反码:5=00000101 对于正数来说不变
-5=11111010 除符号位外全部反转
补码:5=00000101 对于正数来说不变
-5=11111011 在反码的基础上+1
二、常见位运算
运算:&、|、~、^(异或:相异结果为0)
位移:>>(正数高位补0,负数高位补1)、<<、>>>(无符号右移,高位均补0)
三、位运算的运用
1. 取模(取模数为2的n次方)
&
2.判断奇偶
实质:n%2==0?<转换为取模>
3.实现数字翻倍/减半
利用了<<或>>的性质
4.交换两数
a=a^b;
b=a^b; //b=(a^b)^b=a^(b^b)=a
a=a^b; //b=(a^a)^a=(a^a)^b=b
5.只出现一次的数字
一个非空数组,仅有一个元素仅出现一次,其他元素均出现2次,找出此元素
原理:任何一个数字与自己异或结果一定为0。
public int singleNumber(int[] nums)
{
int result=0;
for(int num:nums)
result = result ^ num;
return result;
}
6.比特位计数
给定整数n,对于0<=i<=n中的每个i,计算其二进制表示中1的个数
方法1:x=x&(x-1),清除最低位的1
例如:x=21,其二进制表示为0001 0101
21 & 20 = 0001 0101 & 0001 0100 = 0001 0100 = 20
20 & 19 = 0001 0100 & 0001 0011 = 0001 0000 = 16
16 & 15 = 0001 0000 & 0000 1111 = 0
此时循环进行了3次,对应其一共3个1。
推导:统计n中1的个数[n&(n-1)]+1。
public int[] countBit(int num)
{
int[] bits = new int[num+1] //结果数组
for(int i=1;i<=num;i++) //进行遍历
bits[i]=bit[i&(i-1)]+1;
return bits;
}
方法2:利用奇偶性解决(偶数的1个数必定和其除以2后的数中1的个数相同)
public int[] countBits(int num)
{
int[] bits = new int[num+1];
bits[0]=0;
for(int i=1;i<=nunms;i++)
bits[i] = ((i&1) == 1? bits[i-1]+1 : bits[i>>1]); //与运算:减半(右移)
return bits;
}
7.汉明距离
汉明距离:两个整数对应二进制不同位置的数目
思路:使用按位异或(计算不同位)
public int hammingDistance(int x,int y)
{
int distance = 0;
for(int xor = x^y;xor!=0;xor &= (xor-1))
distance++;
return distance;
}