方法一:
假设n的二进制表达为
n
=
∑
i
=
0
m
a
i
2
i
n=\sum_{i=0}^ma_i2^i
n=i=0∑mai2i其中
a
m
≠
0
a_m\neq 0
am=0。我们知道若n为偶数,
a
0
=
0
a_0=0
a0=0。此时
n
2
=
∑
i
=
1
m
a
i
2
i
−
1
\frac{n}{2}=\sum_{i=1}^ma_i2^{i-1}
2n=i=1∑mai2i−1
故而n的二进位表示中1的个数与n/2的二进制表达中1的个数是一样的。若n为奇数,
a
0
=
1
a_0=1
a0=1。此时
n
−
1
2
=
∑
i
=
1
m
a
i
2
i
−
1
\frac{n-1}{2}=\sum_{i=1}^ma_i2^{i-1}
2n−1=i=1∑mai2i−1故而n的二进位表示中1的个数比
n
−
1
2
\frac{n-1}{2}
2n−1的二进制表达中1的个数多1个。代码如下:
#include <iostream>
using namespace std;
int main()
{
int n, c=0;
cin >> n;
while (n > 0)
{
if (n % 2 == 0)
n = n / 2;
else
{
n = (n - 1) / 2;
c++;
}
}
cout << c << endl;
return 0;
}
方法二(位运算)
这里我们利用位元算中的&来设计算法。我们知道若n是
2
k
2^k
2k这种形式,则n的二进制表示只有1最高位是1其他均是0。若n是
2
k
−
1
2^k-1
2k−1这种形式,则n的二进制表示中每个数位上均是1。因此
2
k
2^k
2k&
2
k
−
1
=
0
2^k-1=0
2k−1=0。假设
n
=
n
0
+
n
1
n=n_0+n_1
n=n0+n1,其中
n
0
=
2
k
,
n
1
=
∑
i
=
k
+
1
m
a
i
2
i
.
n_0=2^k,\quad n_1=\sum_{i=k+1}^ma_i2^i.
n0=2k,n1=i=k+1∑mai2i.则
n
−
1
=
n
0
−
1
+
n
1
=
2
k
−
1
+
∑
i
=
k
+
1
m
a
i
2
i
n-1=n_0-1+n_1=2^k-1+\sum_{i=k+1}^ma_i2^i
n−1=n0−1+n1=2k−1+i=k+1∑mai2i 且
n
&
n
−
1
=
n
1
=
∑
i
=
k
+
1
m
a
i
2
i
.
n\&n-1=n_1=\sum_{i=k+1}^ma_i2^i.
n&n−1=n1=i=k+1∑mai2i.但是n中二进制中1的个数仅比
n
1
n_1
n1多一个。故而可以用这种方式做归纳。代码如下
#include <iostream>
using namespace std;
int main()
{
int n, c=0;
cin >> n;
while (n > 0)
{
n = n & (n - 1);
c++;
}
cout << c << endl;
return 0;
}