每天一道算法题——二进制数中1的个数

本文介绍了一种高效算法,用于计算给定整数二进制表示中1的个数。通过五种不同的实现方法进行讨论,包括基本方法、标准版、进阶版、查表法和平行法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是我在面试时考官问我的一道算法题,但是当时我没有好的想法,只是用最基本的方法写出来的,现在整理一下这道题的思路:
1、不完善版:(问题一:如果把右移换成/2可以吗:不可以,因为除法的效率比移位运算的效率低; 问题二:如果输入的负数会出现什么情况:因为是右移,负数会高位补1,最后陷入死循环)
public int Method1(int binary){
		int count = 0;
		while(binary > 0){
			if((binary&1) == 1){
				count++;
			}
			//count += binary&1;
			binary = binary >> 1;
		}
		return count;
	}


2、标准版:通过设置标志位且让标志位左移避免陷入死循环中。
public int Method2(int binary){
		int count = 0;
		int flag = 1;    //important
		while(flag > 0){
			if((binary&flag)>0){
				count++;
			}
			flag = flag<<1;
		}
		
		return count;
	}

3、进阶版:将二进制数的最右边1删掉,直到这个二进制数为0为止。
public int Method3(int binary){
		int count = 0;
		while(binary > 0){
			count++;
			binary = binary&(binary-1);
		}
		return count;
	}


4、升级版(查表法,平行算法)
查表法:根据奇偶性来分析,如果它是偶数,那么n的二进制中1的个数与n/2中1的个数是相同的,比如4和2的二进制中都有一个1,6和3的二进制中都有两个1。为啥?因为n是由n/2左移一位而来,而移位并不会增加1的个数。如果n是奇数,那么n的二进制中1的个数是n/2中1的个数+1,比如7的二进制中有三个1,7/2 = 3的二进制中有两个1。为啥?因为当n是奇数时,n相当于n/2左移一位再加1。
对于任意一个32位无符号整数,将其分割为4部分,每部分8bit,对于这四个部分分别求出1的个数,再累加起来即可。而8bit对应2^8 = 256种01组合方式,这也是为什么表的大小为256的原因。注意类型转换的时候,先取到n的地址,然后转换为unsigned char*,这样一个unsigned int(4 bytes)对应四个unsigned char(1 bytes),分别取出来计算即可。举个例子吧,以87654321(十六进制)为例,先写成二进制形式-8bit一组,共四组,以不同颜色区分,这四组中1的个数分别为4,4,3,2,所以一共是13个1,如下面所示。
10000111 01100101 01000011 00100001 = 4 + 4 + 3 + 2 = 13
public int Method4(int binary){
		int count = 0;
		if(0>binary || binary>Integer.MAX_VALUE){
			return -1;
		}
		int[] searchTable = new int[256];
		
		for(int i=0;i<256;i++){
			searchTable[i] = (i&1) + searchTable[i/2];
		}
		int flag = 0xff;
		for(int i=0;i<4;i++){
			int tmp = binary&flag;
			flag = flag<<8;
			count+=searchTable[tmp];
		}
		return count;
		/*return table[n &0xff] +
		        table[(n >>8) &0xff] +
		        table[(n >>16) &0xff] +
		        table[(n >>24) &0xff] ;
		*/
	}


5、平行法:
public int Method5(int n){
		n = (n &0x55555555) + ((n >>1) &0x55555555) ;  //5 >> 101  149
	    n = (n &0x33333333) + ((n >>2) &0x33333333) ; //3 >> 011    50
	    n = (n &0x0f0f0f0f) + ((n >>4) &0x0f0f0f0f) ;     //5
	    n = (n &0x00ff00ff) + ((n >>8) &0x00ff00ff) ;   //5
	    n = (n &0x0000ffff) + ((n >>16) &0x0000ffff) ;    //5

	    return n ; 
	}


附录:
int BitCount5(unsigned int n) 
{
    unsigned int tmp = n - ((n >>1) &033333333333) - ((n >>2) &011111111111);
    return ((tmp + (tmp >>3)) &030707070707) %63;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值