2.1求二进制中1的个数
法1:整型数观念。
二进制中1在数中的体现,也就是当一个数是奇数时最末位就是1。那么我们可以将一个数判断是否是奇数。如果是就统计加1。并且/2 失去这一位。
int count; count = 0; void Count(int num) { while(num) { if(num %2 ==1) { count ++; } num /= 2; } }
法2:从二进制的角度。
利用位运算。从二进制的角度对数进行1的统计。
熟悉位运算的用法。暂时介绍 & 按位与 和 >> << 。对于<< >>不过多介绍,就是位的前进的后退。可以理解: >>n 是 /pow(2,n)。 <<n 是 *pow(2,n)。
& 是位之间的运算。
实质上是: 1&0=0 0&0=0 1&1=1
运算举例:1010&1110=1000
有一种用法是取某位。如果取第一位也就是0000001也就是1。
int count; count = 0; void Count(int num) { while(num) { count += (num&1);//位运算的优先级是很慢的。 num >>= 1; } }
法3:利用&的特殊用法。算法时间复杂度根据1的个数的线性时间。
对于&我们不是说了它有一种用处是取位吗?那我们是否可以
num&?=直接可以删除掉最后一位的1呢?答案当然是有的。我们利用逆向思维。来观察这个?满足什么样的特点。这是十分常用的思想方法。
1010&X=1000 X = 1?0?(式子里的问号的意思是可以0也可以是1)
1100&X=1000 X = 10??
1110&X=1100 X = 110?
假若第一个式子1?0? 第二个?假若是0。我们可以发现一个关系。X和num本身的关系。只要num最后的1那一位变成0。前1前面位的数都保留不变。而1后面的由于num的1后面都是0。而满足这种关系的。只要num-1。因为num最后一位后面的数都是0。(当然1也可以是最后一位)。
举例:1100 - 1 = 1001。1110-1 = 1101。1010-1 = 1001。
int count; count = 0; void Count(int num) { while(num) { num = num&(num-1); count ++ ; } }
在本章节,还使用了查表法。(分支操作不讲)。也就是打表。因为byte只有8位 2^8 = 256个状态。完全可以打表。简单hash。所以对于状态数量一定且可以实现的时候完全可以考虑这方面。来用空间换时间。以及这里有位运算的学习。还有逆向思维。和不同角度来观察一个数。另外主要是记录学习编程之美给我带来的思维上的跃进。
根据后文网址http://blog.csdn.net/justpub/article/details/2292823的算法时间分析。打表法并没有想象中那么快。而且同时这提醒了我解法一也不过8次的循环。但我想我们也得考虑一下程序的适用性。