1、直接N%2 == 1 就是一个1
int NumberOf1(unsigned int n)
{
int nNum = 0;
while (n > 0)
{
n = n / 2;
int j = n % 2;
if (j == 1)
{
nNum++;
}
}
return nNum;
}
优化:把n = n / 2; 修改为n>>1,移位运算能大量提高效率
2、在前面的运算中,我们如果要求0-N中1的个数的话,又该怎么做呢?显然一次次调用NumberOf1是不科学的,这势必会浪费很多次计算,我们引入一个知识点N&(N-1)其中N >=1
(1)、首先我们看一下N-1 和N的区别是什么?
假设:N为 XXXX101010
N-1为XXXX101001
那么N&(N-1)= XXXX101000 就能把最右边的1给去掉,那么N中的1个数= N&(N-1) +1 去掉最右边的1再+1
那么这样的话,从0开始到N求得的N中的个数。可以不断应用计算过的数然后+0、+1操作
int[] NumberOf1s(unsigned int num)
{
int[] res = new int[num + 1];
for (int i = 1; i <= num; i++)
{
res[i] = res[i & (i - 1)] + 1;
}
return res;
}
3、回到第一个问题,当N不断变大的时候(几千上E的时候),计算的过程就相当的慢了,我们发现一个unsied int 是由4个8位数据组成的(通用机器)
因此我们可以建表0~256,然后直接去4个里面的1计算
int[] NumberOf1s(unsigned int num)
{
int[] res = new int[num + 1];
for (int i = 1; i <= num; i++) { //注意要从1开始,0不满足
res[i] = res[i & (i - 1)] + 1;
}
return res;
}
int nNumber[257] = NumberOf1s[256];
int NumberOf1(unsigned int n)
{
unsigned char* p = (unsigned char*)&n;
return nNumber[p[0]] +
nNumber[p[1]] +
nNumber[p[2]] +
nNumber[p[3]]; ;
}