n&1:与操作,判断 n 二进制最右一位是否为 1 。
// 若等于1,表示最右一位是1;
// 否则是0.
if ((n & 1) == 1) {
...
}
n&1常用来判断n是奇数还是偶数。
if (n & 1) == 1):
n为奇数
if (n & 1) == 0):
n为偶数
n>>1:移位操作,删除n二进制的最右一位。
n = n>>1;
// 简写如下
n >>= 1;
n&(n-1)为去除整数二进制的最后一个1。
public class Test {
public static void main(String[] args) {
// 5的二进制表示为:101
// 去掉二进制最后一个1,则为:100
// 转换成10进制为:4
System.out.println(5&(5-1)); // 4
// 1010
System.out.println(10&(10-1)); // 8
// 1001
System.out.println(9&(9-1)); // 8
}
}
一.n&(n-1)的原理和应用
1.原理
在“力扣”中第一道题目就是求一个32位二进制数串中1的个数,在评论区看到这种方法求解,原理附下:
对于一个二进制数(此处设定长度为8位,任何长度同理)n,举例:n=xxxxxxx1,n-1=xxxxxxx0,n和n-1进行&运算,结果为n&(n-1)=xxxxxxx0,由此可见,在n和n-1进行&运算 之后,将n中最末位的1转化为0。再来看一个例子,假如n=xxxx1000,n-1=xxxx0111,n和n-1进行&运算,结果为n&(n-1)=xxxx0000。总结:在一个二进制数串中,只要有1存在,不论1的位置在哪里,进行n&(n-1)的运算之后,总能将最末位的1化为0。
2.应用
了解并掌握以上原理之后,就可以来做这道统计二进制数串中1的个数的题目啦。先上代码:
public class Solution {
public int hammingWeight(int n) {
int ret = 0;
while (n != 0) {
n &= n - 1;
ret++;
}
return ret;
}
}
透过代码,可以看到,在while循环里,当二进制数串n不等于0(即有1存在)时候,对其进行n&(n-1)运算,并在循环外定义一个初始值为0的整数ret。循环体中,每进行一次&运算,计数值ret就加1,这样,当n=0时(即n中的所有1都被0取代),不再进行&运算,同时返回计数值ret,此值就代表n中1的个数。
二.n&(1<<i)的原理和应用
1.原理
首先来明确1<<i的意义,1<<i代表将1左移i位,举例:当i=3时,即为1<<3,结果为(000)1->1000(对于任意一个非0二进制数,我们都可以假定它前边有无数个0,此处1就可以写为0001)。简言之,就是i的值为多少,从右向左计数,第i位的值就为1,其余值为0。由于1左移之后,只有第i位(从右往左计数)是1,其余为都是0,与另一个二进制数n进行&运算,得到的结果可以用来表示n的第i位(从右向左计数)为1还是为0。
2.应用
public class Solution {
public int hammingWeight(int n) {
int ret = 0;
for (int i = 0; i < 32; i++) {
if ((n & (1 << i)) != 0) {
ret++;
}
}
return ret;
}
}
透过代码,可以看到,i从0到31(此处的二进制数串位数为32,其他的即为数串长度减1),每一位都进行按位&运算,如果运算结果不等于0,即代表此位为1,计数值ret从0开始计数,每次&运算结果不为0,ret值就加1。当n的所有位置都与1<<i进行&运算之后,结束循环,返回ret值.