剑指offer---二进制中1的个数

剑指offer—二进制中1的个数

问题分析

本题是为了求解一个整数的二进制中1的个数。比如9(1001),它的二进制数就有两个1。
这类的题目大部分都会用到位运算的知识,位运算非常抽象,而且在日常的生活中很少碰到,但是位运算的核心很简单,因为位运算的种类就那么几个(或、与、非、异或、左移和右移),所以只要将这些基本的操作熟记于心,这类的题目就好做了。
回到上面这题。第一种解法就是不断的将这个数进行右移操做,直到这个数变为零,每次检查最低为是否为1,如果为1,那么1的个数就加1。比如9,右移的操作结果分别为1001 >> 100 >> 10 >> 1 >> 0,只有1001和1末位为1,只有这两个数与1做与运算结果为1,所以结果为2。
细心的同学很快就会发现,如果给的数是一个是负数,那么右移的话每次都会在左边补1,那这样就陷入了一个死循环中,程序出错。

下面是第二个方法,既然题目所给的数在移位的时候可能会是负数,进而出现死循环,那么我们是否可以找一个不会出现死循环的数?在上面的每次移位后都会与1进行与运算,就是用“1”来检测每一位是否是1,既然这样那么可不可以让“1”移动呢?当然可以的,我们可以让1不断的左移,这样就不断的在右边补零。开始将1设为unsigned int,所以右移32位后,就会变成0,这样就可以作为一个循环停止的条件。

第二种解答会执行32次操作,这样来做还是有点多。既然所给的数的二进制中1的个数有限,那么能不能每一次操作都能“剥离”一个1呢?这种解法相比较前面的两个方法要复杂一点,要对位运算具有很好的理解。首先,当给定的数不为0时,说明二进制中含有1,先将1的次数加上1,接下来将给的数减1。减1后有一个效果就是从右往左的第一个1变成0,1右边的0全部变为1,左边的1和0保持不变。接下来就是与运算上场了,这两个数直接相与,那么原来右往左的第一个1以及后面的数全部都变成了0,至此就完成了1的“剥离”(如9的1001和1000相与结果为1000,“剥离”了一个1)!后面就是循环操作相与后结果,直至结果变为0。

源码

// 第二种解法
int numbersOfOneNormalVer(int number){
	int count = 0;
	unsigned int flag = 1;
	while (flag){
		if (number & flag)
			count += 1;
		flag <<= 1;
	}

	return count;
}

// 第三种解法
int numbersOfOneSpecialVer(int number){
	int count = 0;
	while (number){
		++count;
		number &= (number - 1);
	}

	return count;
}

谢谢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值