初看这个题目,给人的第一感觉是要把整数转化成二进制表示,然后在求出里面的1的个数,于是诞生了第一种解法
1、除余法
我们都知道”除余法“可以将十进制数转化为其二进制数,对于余数,从下往上取构成其二进制表示。那么我们可以根据每次的余数是否为1,判断1的个数
int Count(int n)
{
int cnt=0;
while(n)
{
if(n%2==1) //如果余数为1,则个数加1
cnt++;
n=n/2;
}
return cnt;
}
时间复杂度:O(logn)
空间复杂度:O(1) //即用了一个变量cnt
2、移位+与操作
对于一个整数,我们可以进行移位操作,每向右移一位,相当于原来整数除以2。
那么我们可以先从最后一位进行判断,统计是否为1;然后向右移一位,然后再判断最后一位,如此循环下去
通过对整数移位:
int Count(int n)
{
int cnt=0;
while(n)
{
cnt+=n&1;
n=n>>1;
}
return cnt;
}
时间复杂度:O(m) //m表示整数的二进制位数
空间复杂度:O(1)
3、与操作
可以通过求n和n-1的与操作来实现,因为n-1相当于对n中最右的1及其后面进行了非操作,如10的二进制1010,9的二进制1001,最后的两位由”10“变成了”01“,
因而n中当前‘1’及其后面的都变成了0
初始:
n=1010 (二进制)
10&=(10-1)
得到1010 & 1001= 1000,
cnt=1
8&=(8-1)
得到1000 & 0111= 0000,
cnt=2
停止循环
int Count(int n)
{
int cnt=0;
while(n)
{
n&=(n-1);
cnt++;
}
return cnt;
}
空间复杂度:O(1)
扩展问题:给定两个正整数(二进制表示)A和B,问把A变成B需要改变多少位?
解析:也即两者二进制位有多少位不同,可用第二种方法:移位
int DiffCount(int m, int n)
{
int cnt=0;
int flag=1;
while(m && n)
{
if((m&flag)!=(n&flag)) //每次比较最后一位是否相同
cnt++;
m >>=1; //右移一位
n >>=1;
}
while(m)
{
if(m&flag ==1) //由于此时n为0,故只需统计m中剩余的1的个数
cnt++;
m >>=1;
}
while(n)
{
if(n&flag==1) //由于此时m为0,故只需统计n中剩余的1的个数
cnt++;
n >>=1;
}
return cnt;
}