Algorithm --> 二进制中1的个数

时间:2024-10-06 21:05:14

行文脉络

  1. 解法一——除法
  2. 解法二——移位
  3. 解法三——高效移位
  4. 解法四——查表
  5. 扩展问题——异或后转化为该问题

对于一个字节(8bit)的变量,求其二进制“1”的个数。例如6(二进制0000 0110)“1”的个数为2,要求算法效率尽量高。

解法一

对于二进制数来说,除一个2,就少一位,可以判断这个少的位来确定“1”的个数。

例如:6(0000 0110)

0000 0110 / 2 = 0000 0011     ----少的一位为0

0000 0011 / 2 = 0000 0001     ----少的一位为1

0000 0001 / 2 = 0000 0000     ----少的一位为1

操作数数已经为0,到此结束

参考代码

int Count_1(int val)
{
int num = ;
while(val)
{
if(val % != ) //用取模获得去除的一位
++num;
val /= ;
}
return num;
}

性能:时间复杂度O(log2v),即二进制数的位数;空间复杂度O(1)

解法二

对于二进制数来说,除法是用移位完成。

例如:6(0000 0110)

0000 0110 >> 1 = 0000 0011     ----少的一位为0

0000 0011 >> 1 = 0000 0001     ----少的一位为1

0000 0001 >> 1 = 0000 0000     ----少的一位为1

操作数数已经为0,到此结束

参考代码

int Count_2(int val)
{
int num = ;
while(val)
{
if(val & != ) //用与1与获得移除的一位
++num;
val >>= ;
}
return num;
}

性能:时间复杂度O(log2v),即二进制数的位数;空间复杂度O(1)

解法三

对于上述算法,有个问题,比如1000 0000,大把的时间用在没用的0上,最好寻求一种直接判断“1的个数。

通过观察可以找到规律:对于数a, a = a & (a-1)就可以去除a的最后一个1

例如:6(0000 0110)

0000 0110 & 0000 0101 = 0000 0100

0000 0100 & 0000 0011 = 0000 0000

操作数数已经为0,到此结束

参考代码

int Count_3(int val)
{
int num = ;
while(val)
{
val &= (val -);
++num;
}
return num;
}

性能:时间复杂度O(M),即二进制中“1”的个数,空间复杂度O(1)

解法四

查表法,把0~255这256个数的结果全部存储在数组中,val直接作为下标,countTable[val]即为结果。典型的用空间换时间。

参考代码

int Count_5(int val)
{
int countTable[] = {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , };
return countTable[val];
}

性能:时间复杂度:O(1), 空间复杂度O(N)

整个程序执行参考

#include<iostream>
using namespace std; int Count_1(int val)
{
int num = ;
while(val)
{
if(val % != )
++num;
val /= ;
}
return num;
} int Count_2(int val)
{
int num = ;
while(val)
{
if(val & != )
++num;
val >>= ;
}
return num;
} int Count_3(int val)
{
int num = ;
while(val)
{
val &= (val -);
++num;
}
return num;
}
int Count_5(int val)
{
int countTable[] = {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , };
return countTable[val];
} int main()
{
int a = , b = ;
cout << "Num of 1:" << Count_1(a) << endl;
cout << "Num of 1:" << Count_2(a) << endl;
cout << "Num of 1:" << Count_3(a) << endl;
cout << "Num of 1:" << Count_5(b) << endl;
cout << "Num of 1:" << Count_1(b) << endl;
cout << "Num of 1:" << Count_2(b) << endl;
cout << "Num of 1:" << Count_3(b) << endl;
cout << "Num of 1:" << Count_5(b) << endl;
}

结果

Algorithm --> 二进制中1的个数

扩展问题

1. 给定两个正整数(二进制表示)A、B,如何快速找出A和B二进制表示中不同位数的个数。

  思路

  首先A和B进行异或操作,然后求得到的结果中1的个数(此问题)。

2. 判断一个数是否是2的幂

bool powerof2(int n)
{
return ((n & (n-)) == );
}

相关文章