[剑指offer]面试题10:二进制中1的个数

Posted Wecccccccc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[剑指offer]面试题10:二进制中1的个数相关的知识,希望对你有一定的参考价值。

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

❖ 可能引起死循环的解法

代码如下:

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

面试官看了代码之后可能会问:把整数右移一位和把整数除以 2 在数学上是等价的,那上面的代码中可以把右移运算换成除以 2 吗?答案是否定的。因为除法的效率比移位运算要低得多,在实际编程中应尽可能地用移位运算符代替乘除法。

面试官接下来可能要问的第二个问题就是:上面的函数如果输入一个负数,比如0x80000000,运行的时候会发生什么情况?
把负数0x80000000右移一位的时候,并不是简单地把最高位的1移到第二位变成0x40000000,而是0xC0000000。这是因为移位前是个负数,仍然要保证移位后是个负数,因此移位后的最高位会设为1。
如果一直做右移运算,最终这个数字就会变成0xFFFFFFFF而陷入死循环。

❖ 常规解法
为了避免死循环,我们可以不右移输入的数字i。首先把i和1做与运算,判断i的最低位是不是为1。接着把1左移一位得到2,再和i做与运算,就能判断i的次低位是不是1……这样反复左移,每次都能判断i的其中一位是不是1。基于这种思路,我们可以把代码修改如下:

int CountNumbers(int n)
{
	int count = 0;
	unsigned int flag = 1;
	while (flag)
	{
		if (n & flag) count++;
		flag = flag << 1;
	}
	return count;
}

这个解法中循环的次数等于整数二进制的位数,32 位的整数需要循环32次。

❖ 能给面试官带来惊喜的解法

把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0。那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。基于这种思路,我们可以写出新的代码:

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

测试用例:
● 正数(包括边界值1、0x7FFFFFFF)。
● 负数(包括边界值0x80000000、0xFFFFFFFF)。
● 0。
本题考点:
● 考查对二进制及位运算的理解。
● 考查分析、调试代码的能力。如果应聘者在面试过程中采用的是第一种思路,当面试官提示他输入负数将会出现问题时,面试官会期待他能在心中运行代码,自己找出运行出现死循环的原因。这要求应聘者有一定的调试功底。

以上是关于[剑指offer]面试题10:二进制中1的个数的主要内容,如果未能解决你的问题,请参考以下文章

剑指offer面试题 15. 二进制中 1 的个数

Leetcode---剑指Offer题15---二进制中1的个数

Leetcode---剑指Offer题15---二进制中1的个数

剑指Offer对答如流系列 - 二进制中 1 的个数

剑指offer 面试43题

《剑指offer》第十五题:二进制中1的个数