二进制中1的个数 -- java
题目描述
请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如,把9表示成二进制是1001,有两位是1.因此,如果输入9,则该函数输出2。
题目考点
考察应聘者对二进制及位运算的理解。
解题思路
常规解法
首先把n和1做与运算,判断n的最低位是不是为1,接着把1左移一位得到2,再和n做运算,就能判断n的次低位是不是1…这样反复左移,每次都能判断n的其中一位是不是1。
能给面试官带来惊喜的解法
我们基于这样一个事实:把一个整数减去1之后再后原来的整数做位与运算,得到的结果相当于把整数的二进制表示中最右边的1变成0。
例子如下:
n : 10110100
n-1 : 10110011
n&(n-1) : 10110000
那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。
Java自带API解法
Integer.bitCount(n);
代码
常规解法
public class NumberOf1 {
public static int numberOf1(int n) {
int count = 0;
int flag = 1;
while (flag != 0) {
if ((n & flag) != 0) {
count++;
}
flag = flag << 1;
}
return count;
}
public static void main(String[] args) {
System.out.println(numberOf1(9));
}
}
能给面试官带来惊喜的解法
public class NumberOf1 {
public static int numberOf1(int n) {
int count = 0;
while (n != 0) {
count++;
n = n & (n-1);
}
return count;
}
public static void main(String[] args) {
System.out.println(numberOf1(9));
}
}
补充
位运算只有5种运算:与、或、异或、左移和右移。
与、或、异或运算就是简单的真值表。
左移运算符 m<<n 表示把 m 左移 n 位。在左移 n 位的时候,最左边的 n 位将被丢弃,同时在最右边补上 n 个0.
右移运算符 m>>n 表示把 m 右移 n位。在右移 n 位的时候,最右边的 n 位将被丢弃,但右移时处理最左边位情形有两种情况,如果数字是无符号数字,则用0填补最左边的 n 位;如果数字是一个有符号数值,则用数字的符号位填补最左边的 n 位。也就是说,如果数字原先是一个正数,则右移之后再最左边填补 n 个0;如果数字原先是负数,则右移之后在最左边补 n 个1。
负数的二进制表示(计算机用补码表示负数)
变成原码:将绝对值转换成二进制数,然后在最高位补1
变成反码:对原码除符号位外各位取反
变成补码:在反码最后一位加1
问题: 把整数右移一位和把整数除以2在数学上是等价的吗?
不是,除法的效率比一位运算效率低得多,在实际编程中应尽可能得用一位运算符代替乘除法。
值得注意的地方:
把一个整数减去1之后再后原来的整数做位与运算,得到的结果相当于把整数的二进制表示中最右边的1变成0。 很多二进制问题都可以用这种思路解决。
来自
《剑指Offer》
Coding-Interviews/二进制中1的个数.md at master · todorex/Coding-Interviews