请实现一个函数,输入一个整数输出该数二进制表示一的个数,例如把9表示成二进制,是1001,有两位是1,因此如果输入就该函数输出2。
刚开始看到这个题,我们就很容易想出这样一个方法。我们先判断这个数的从右边数第一位是不是一?这个可以很简单的用这个数与1进行与操作来实现。之后我们将这个数向右移一位。再像刚才一样判断从右边数第二位是不是一,我们可以一直这样循环下去,一直到这个数变为零为止。
这种方法很好想到也很好实现,但是有一个问题,当我们这个数是负数的时候,但他右移会补一。最后会使我们这个数变为0x1111111。我们这个循环就会变成了死循环。这个循环永远也不会结束。
private static int findNumberOf1One(long test) {
// TODO Auto-generated method stub
/*
* test不断右移和1相与的方法
*
*/
if (test > Long.MAX_VALUE || test < Long.MIN_VALUE) {
throw new RuntimeException("输入数字过大或过小");
}
int num = 0 ; //1的个数
int x = 1 ; //相与的对象
long tmp = test; //中间变量
while (tmp != 0) {
if ((tmp&x) != 0) {
num++;
}
tmp = tmp >>> 1;
}
return num;
}
第二种方法:
private static int findNumberOf1Second(long test) {
// TODO Auto-generated method stub
/*
* test 与 1及1左移后的数相与的方法
*
*/
if (test > Long.MAX_VALUE || test < Long.MIN_VALUE) {
throw new RuntimeException("输入数字过大或过小");
}
int num = 0 ; //1的个数
long x = 1 ; //相与的对象
long tmp = test; //中间变量
while (0 != x) {
if ((tmp&x) != 0) {
num++;
}
x = x << 1;
}
return num;
}
最后,剑指offer上还写了这样一种解法。我们可以利用这样一个规律,把一个整数减去一再和原整数作与操作,会把该整数最右边一个一变为零,那么一个整数的二进制表示中有多少个一,就可以进行多少次这样的操作。
这里,我们举个例子来看:
若一个数末尾是1 : 例如 -1: 补码表示为 1111...1111(16个1) 减去1 ,变成-2 即1111...1110
若一个数末尾是1: 例如9 : 补码表示为 0000..........1001 减去1, 变成8 即1111...1000
实现代码如下:
private static int findNumberOf1Third(long test) {
// TODO Auto-generated method stub
/*
* 将test 与 test - 1相与的方法
*/
if (test > Long.MAX_VALUE || test < Long.MIN_VALUE) {
throw new RuntimeException("输入数字过大或过小");
}
int num = 0;
while(test != 0){
num++;
test = test&test-1;
}
return num;
}