位运算 \red{\huge{位运算}} 位运算
①. n n n的二进制位第 k k k位是什么?
此处的第 k k k位是从 1 1 1开始的,但是二进制的位数是从 0 0 0开始的,也就是说 0 0 0位是第 1 1 1位。
解决这个问题需要两个步骤:
- 把第
k
k
k位移动到最后一位:
n > > k − 1 n>>k - 1 n>>k−1 - 看个位的数字是什么:
x & 1 x\space \& \space 1 x & 1
1.2步骤综合:
n
>
>
(
k
−
1
)
&
1
n \space >> \space (k - 1) \space \& \space 1
n >> (k−1) & 1
代码实现
#include <iostream>
using namespace std;
int main ()
{
int n;
cin >> n;
int k;
cin >> k;
cout << n >> (k - 1) & 1 << endl;
return 0;
}
②. n n n的二进制表示之中有多少个 1 1 1
要解决这个问题首先先看一个知识点: l o w b i t lowbit lowbit
l o w b i t lowbit lowbit操作
定义 o r or or作用
用来求解一个二进制数从低位到高位,第一个
1
1
1形成的二进制数。
例如
1001000
1001000
1001000,进行
l
o
w
b
i
t
lowbit
lowbit操作之后,返回的结果是
1000
1000
1000(返回的结果也是一个二进制数)。
核心操作及其推理
核心操作:
x & − x = x & ( − x + 1 ) x\space \& \space -x \space = \space x \space \& \space (-x \space + \space 1) x & −x = x & (−x + 1)
推理:
假定有:
x
=
1010.....
(
1
)
000
x = 1010..... (1)000
x=1010.....(1)000
−
x
=
0101.....
(
0
)
111
-x = 0101.....(0)111
−x=0101.....(0)111
−
x
+
1
=
0101.....
(
1
)
000
-x + 1 = 0101.....(1)000
−x+1=0101.....(1)000
x
&
(
−
x
+
1
)
=
0000.....
(
1
)
000
x \& (-x + 1) = 0000.....(1)000
x&(−x+1)=0000.....(1)000
观察可以知道
x
&
−
x
=
x
&
(
−
x
+
1
)
x\space \& \space -x \space = \space x \space \& \space (-x \space + \space 1)
x & −x = x & (−x + 1)
得证,说明了
x
&
−
x
x\&-x
x&−x就可直接返回一个数二进制数第一位
1
1
1和低位构成的二进制数。
原问题处理
有了 l o w b i t lowbit lowbit操作之后,可以开始对原问题进行求解。
思路
对于原数,每次都用 l o w b i t lowbit lowbit操作减去最小位 1 1 1对应的二进制数,并记录次数,直到原数减成 0 0 0为止。
代码实现
#include <iostream>
using namespace std;
int lowbit(int x)
{
return x & -x;
}
int main ()
{
int n;
cin >> n;
while(n--)
{
int x;
cin >> x;
int res = 0;
while(x)
{
x -= lowbit(x);
res++;
}
cout << res << ' ';
}
return 0;
}