编程之美-求二进制1的个数

一个在常见的题目,但是看到编程之美的时候才发现,方法真多,今天来总结一下:

解法一

可以举出一个八位的二进制例子来进行分析。对于一个二进制操作,我们知道,除以一个2,原来的数字将会减少一个0,如果除的过程中有余,那么就表示当前位置有一个1.

以10 100 010为例:

第一次除以2时,商为 1 010 001,余为 0。

第二次除以2时,商为 101 000,余为1。

因此可以根据整型除法的特点求解,代码如下:

public int countBit1(int n) {
		int num = 0;
		while (n != 0) {
			if (n%2 == 1) {
				num++;
			}
			n /= 2;
		}
		return num;
	}

解法二

显然解法二不是最优的,熟悉计算机的都知道,除法的底层是怎么实现的,当然是按移位来完成的,所以移位版的代码

public int countBit2(int n) {
		int num = 0;
		while (n != 0) {
			if ((n & 0x01) == 1) {
				num++;
			}
			n >>>= 1;
		}
		return num;
	}

代码是不是有点长,在简化下:

public int countBit21(int n) {
		int num = 0;
		while (n != 0) {
			num += (n & 1);
			n >>= 1;
		}
		return num;
	}

解法三

看完上面那个算法,都算是很多人的极限了,在也想不出了好的办法了。分析上面那个算法的复杂度,如果是一个8Bit的整型,需要遍历8次,32Bit的,需要遍历32次。

我们的目的是计算出1的个数,但是我们为啥要去遍历0呢?比如8bit的32: 00 100 000,我们在浪费在了判断是否为0,所以思路来了,直捣黄龙,算法复杂度只与1的个数有关,上代码:

public int countBit3(int n) {
		int num = 0;
		while (n != 0) {
			n &= (n-1);//每一次去掉最右边的一个1(二进制)
			num++;
		}
		return num;
	}

解法四

到此为止,还有没有更高效的方法?《编程之美》给出的方法是用空间换时间,直接给出Table表,然后直接查询。在频繁使用此函数,此思路也是可取的。但是这个表示怎么生成的?难不成是一个一个数的么?肯定不是,上代码:

static const unsigned char BitsSetTable256[256] =
{
#   define B2(n) n,     n+1,     n+1,     n+2
#   define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2)
#   define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2)
   B6(0), B6(1), B6(1), B6(2)
};
// To initially generate the table algorithmically:
BitsSetTable256[0] = 0;
for (int i = 0; i < 256; i++)
{
   BitsSetTable256[i] = (i & 1) + BitsSetTable256[i / 2];
}

为啥突然改C版本了,因为这段代码太难了,也没细看,多层递归。牛逼的读者可以解答一下。

解法五

是不是疯了,还有解法?对,最后一个大招。。。

public int countBit4(int v) {
		int c; // store the total here
		int S[] = {1, 2, 4, 8, 16}; // Magic Binary Numbers
		int B[] = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF};

		c = v - ((v >> 1) & B[0]);
		c = ((c >> S[1]) & B[1]) + (c & B[1]);
		c = ((c >> S[2]) + c) & B[2];
		c = ((c >> S[3]) + c) & B[3];
		c = ((c >> S[4]) + c) & B[4];
		return c;
	}

有没有感觉要疯,给个link自己看吧,大招实在是太多了。。。

http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel

时间: 2024-08-28 18:34:23

编程之美-求二进制1的个数的相关文章

编程之美——二进制数中1的个数

解法一:若二进制末尾为1,则除以2余1: int count(int a) { int num=0; while(a) { if(a%2==1) ++num; a=a/2; } return num; } 解法二:使用移位操作相除: int count(int a) { int num=0; while(a) { num+=a&0x01; a>>=1; } return num; } 解法三:以上两种算法复杂度log2(t),t为a的二进制表示位数,若要求复杂度仅与二进制表示中1的个数

编程之美----求二进制数中1的个数

学到的知识点:将一个数和它本身减一作与运算,如果结果为0,说明这个数表示成二进制数时里面有且仅有一个1.于是乎,下面这段代码可以用来求一个数中1的个数. 1 int Count(BYTE v) 2 { 3 int num=0; 4 while(v) 5 { 6 v &= (v-1); 7 num++; 8 } 9 return num; 10 } 另外,如果要求的数位数比较小,可以用hash表来做个预处理,这样可以用o(1)的时间求解.

编程之美---求二叉树中节点的最大距离

如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的,我们姑且定义"距离"为两节点之间边的个数.写一个程序求一棵二叉树中相距最远的两个节点之间的距离. 解法:用递归的方法 1 // 数据结构定义 2 struct NODE 3 { 4 NODE* pLeft; // 左子树 5 NODE* pRight; // 右子树 6 int nMaxLeft; // 左子树中的最长距离 7 int nMaxRight; // 右子树中的最长距离 8 char chValue; // 该节点

2015编程之美资格赛 回文子序列个数

时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定字符串,求它的回文子序列个数.回文子序列反转字符顺序后仍然与原序列相同.例如字符串aba中,回文子序列为”a”, “a”, “aa”, “b”, “aba”,共5个.内容相同位置不同的子序列算不同的子序列. 输入 第一行一个整数T,表示数据组数.之后是T组数据,每组数据为一行字符串. 输出 对于每组数据输出一行,格式为”Case #X: Y”,X代表数据编号(从1开始),Y为答案.答案对100007取模. 数据范围 

编程之美之高速寻找多个数满足给定条件

一.寻找三个数之和等于给定值 分析:方法类似与2Sum.就是先对数组进行排序,时间复杂度为O(nlogn),然后固定一个数,用两个指针进行遍历,找到三个数之和等于给定的值就可以,时间复杂度为O(n^2).详细可提交于leetcode:https://oj.leetcode.com/problems/3sum/,代码例如以下: vector<vector<int> > threeSum(vector<int> &num,int target){ vector<

编程之美---求数组中最长递增子序列

写一个时间复杂度尽可能低的程序,求一个一维数组(N个元素)中最长递增子序列的长度. 解法一:用动态规划,找出以当前元素结尾的最大递增子序列长度.dp[i+1] = max{1, dp[i]+1} ,array[i+1]>array[k] ,k<=i; 复杂度为o(n*n + n). 解法二:另外开一个数组保存长度为i的递增子序列的长度最大的最后一个元素最小的值,然后当处理数组中第i个元素时,从当前最大子序列的长度开始递减,依次寻找直到arrary[i]大于当前最大子序列长度的末尾元素值,然后更

编程之美 求二叉树中节点之间最大的距离

#include<iostream> using namespace std; //二叉树 节点结构 typedef struct TNODE_ { int data; struct TNODE_*left; struct TNODE_*right; }TNode; //获取树的高度=路径+1(最长路径经过的边数+1) int GetLRDistance(TNode*t) { int len=0; if(t==NULL) { return 0; }else{ int lenL=GetLRDis

求二进制1的个数

int BitCount2(unsigned int n) { unsigned int c =0 ; for (c =0; n; ++c) { n &= (n -1) ; // 清除最低位的1 } return c ; } 来自为知笔记(Wiz) 附件列表

求二进制数中1的个数(编程之美)

求二进制数中1的个数 继京东618店庆时买的<编程之美>这本书,翻了翻,发现里面的题还是挺有意思的,看起来我们觉得很简单的题目,解法却有很多很多种,真是一个比一个巧妙,于是,决定记录一下. 书中的题目如下 对于一个字节(8bit)的无符号数,求其二进制表示中"1"的个数,要求算法的执行效率尽可能高. 就像书中给我们说的一样,我们一般人可能想到的解决方法如下 int countOne(int n){ int count=0; while(n){ if(n%2==1){ cou