题目:
请实现一个函数,输入一个整数,输出该整数的二进制表示中1的个数。例如,把9表示成二进制是1001,有2个是1。因此,如果输入9,则该哈数输出2。如果输入负数,则统计该数字二进制补码中的1的个数。
分析:
可能引起死循环的解法:
先判断二进制中最右边一位是不是1;接着把输入的整数右移一位,此时原来处于从右边数起第二位被移到最右边了,再判断是不是1;这样每移动一位,直到整个整数变成0为止。判断最右边一位是不是1,只需要将这个数和1做与运算看结果是不是0就知道了。
假设,这个数字是负数,在右移的过程中,要保持最左边一位符号位不变,最左侧添加一个1,在不断右移的过程中,这个数字最终变成了0xFFFFFFFF,于是就陷入了死循环。
常规解法:
为了避免死循环,我们可以不右移数字,而是不断的左移1,从而判断每一位是1还是0。
能给面试官带来惊喜的解法:
考虑将数字减去1。假设二进制数字是1111,减去1是1110;假设数字是1100,减去1是1011。将1111和1110做与运算得到1110,将1100和1011做与运算得到1000。对于1111到1110,最后一个1不见了,对于1100到1000,也是最后一个1不见了。所以,可以通过n&(n-1)的方式不断去掉二进制中最后一个1,当这个数字变成0的时候,就能统计出来1的数量了。此时的时间复杂度由二进制中1的数量决定,而不是二进制的位数决定,这是一个常数级别的优化。
解法:
可能引起死循环的解法:
package com.wsy;
public class Main {
public static void main(String[] args) {
int n = 15;
int count = getCountOf1(n);
System.out.println(count);
}
public static int getCountOf1(int n) {
int count = 0;
while (n != 0) {
if ((n & 1) == 1) {
count++;
}
n >>= 1;
}
return count;
}
}
常规解法:
package com.wsy;
public class Main {
public static void main(String[] args) {
int n = 15;
int count = getCountOf1(n);
System.out.println(count);
}
public static int getCountOf1(int n) {
int count = 0;
int flag = 1;
while (flag != 0) {
if ((n & flag) != 0) {
count++;
}
flag <<= 1;
}
return count;
}
}
能给面试官带来惊喜的解法:
package com.wsy;
public class Main {
public static void main(String[] args) {
int n = 15;
int count = getCountOf1(n);
System.out.println(count);
}
public static int getCountOf1(int n) {
int count = 0;
while (n != 0) {
n &= (n - 1);
count++;
}
return count;
}
}