二进制中1的个数(Java)

题目:

请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1。因此如果输入9,该函数输出2。

知识点:

这道题是考查位运算。位运算一共有5种:与、或、异或、左移和右移。

与运算特点:全真为真;或运算特点:全假为假;异或运算的特点:相同为假。

左移:m<<n,表示把m左移n位。左移n位的时候,最左边的n位将被丢弃,同时在最右边补上n个0。

右移:m>>n,表示把m右移n位。右移n位的时候,最右边的n位将被丢弃。注:如果数字是一个无符号值,则用0填补最左边的n位。如果数字是一个有符号数值,则用数字的符号位填补最左边的n位。(符号位为0填补0,符号位为1填补1)。

第一想法:

先判断整数二进制表示中的最右边一位是不是1。接着把输入的整数右移一位,此时原来还处于右边数起的第二位被移到最右边了,再判断是不是1。这样每次移动一位,直到整个整数变成0为止。(判断是不是的条件是整数和1做位与运算看结果是不是0就知道了)。

实现代码:

public int numberOf1(int n){
	int count = 0;
	while(n!=0){
		if((n&1) != 0){
			++count;
		}
		n = n >> 1;
	}
	return count;
}

但是从上面的右移规则的定义可以看出如果符号位为1时,这个程序会陷入死循环。故这个代码符合符号位不为1的题目。

改良思路:

为了避免死循环的发生,我们不右移数字n。我们左移1,即首先把n和1做位与运算,判断n的最低位是不是为1。接着把1左移一位得到2,再和n做与运算,就能判断n的次低位是不是1.....,这样反复左移,每次都能判断n的其中一位是不是1。

实现代码:

public int numberOfs1(int n){
	int count = 0;
	int flag = 1;
	while(flag!=0){
		if((n&flag) != 0){
			++count;
		}
		flag = flag << 1;
	}
	return count;
}

优化思路:

把一个整数减去1,再和原来整数做与运算,会把该整数最右边一个1变成0,。那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。

public int numbersOf1(int n){
	int count = 0;
	while(n != 0){
		++count;
		n = (n-1) & n;
	}
	return count;
}

小结:

考查对二进制及位运算的理解。以及思考问题的全面性。

拓展题:

题目:

用一条语句判断一个整数是不是2的整数次方。

思路:

一个整数如果是2的整数次方,那么它的二进制表示中有且只有一位是1,而其他所有位都是0。故把这个待测整数减去1后再和它自己做与运算,这个整数中唯一的1就会变成0。

代码:

public boolean judgeNum2Square(int num){
	if((num & (num-1)) != 0){
		return false;
	}else{
		return true;
	}
}

题目:

输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n。比如:10的二进制位1010,13的二进制位1101,1010改变3位才能变成1101。

思路:

第一步求这两个数的异或结果;第二步统计异或结果中1的位数。

代码:

public int changeCount(int n, int m){
	int count = 0;
	int x = n^m;
	while(x!=0){
		++count;
		x = (x-1) & x;
	}
		return count;
}

小思:

把一个整数减去1之后再和原来的整数做位与运算,得到的结果相当于是把整数的二进制表示中的最右边一个1变成0。这个方法在解决很多二进制问题都可以用。

小结:

基础很重要啊,充分理解位运算。

猜你喜欢

转载自blog.csdn.net/u013132035/article/details/80554731