文章目录
写在前面
与运算,是一种常用的二进制运算,其真值表如下
x | y | x&y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
(有0为0,全1才为1)
与运算的常见应用
判断奇偶性
奇数一定是二的倍数加一得到的,所以二进制表示的末尾就一定是1(二进制最后一位对应于十进制就是 2 0 2^0 20),同理偶数的二进制末尾就一定是0。所以利用这个性质我们就可以用于判断奇偶数
bool check(int n) {
return n&1;
}
取出某几位
用一个二进制位与上1以后一定还是原数,一个数与上0以后一定是0的性质可以取出一个数的某几位。还有利用给定数字范围最大的数二进制位有多少位可以用来消除某些数位
2的幂的判定
一个数若为2的幂,那么他的二进制表示一定是00…0100…00这样的。因为在二进制中每一位的含义就是二的n次方,若二进制表示中只有一个1,那么必然是2的幂。因为进位的关系2的幂减一的二进制表示一定全是1。这样相与的结果就是0。
bool check(int n) {
return n&(n-1);
}
取出二进制最低位的一个1和后面的0组成的数
负数的二进制就是正数取反加一,用一个正数和其对应负数与在一起就可以得到二进制最低位的一个1和后面的0组成的数。这就是很常见的lowbit函数
x | ob(x) |
---|---|
10 | 1010 |
-10 | 0110 |
lowbit | 10 |
int lowbit(int n) {
return n&-n;
}
课后习题
191. 位1的个数
一直右移判断每一个二进制位是不是1
class Solution {
public:
int hammingWeight(uint32_t n) {
int cnt=0;
while(n) {
if(n&1) cnt++;
n>>=1;
}
return cnt;
}
};
1356. 根据数字二进制下 1 的数目排序
建一个二维数组,tu[i][j]存放实际的数字,i表示该数字二进制下1的数目,j表示表示当前存放的位置(每一行都用数组模拟了一个队列,第一维坐标就是队列的索引)
class Solution {
public:
vector<int> sortByBits(vector<int>& arr) {
int tu[35][510]={0},cnt[35]={0};
vector<int>res;
for(auto t:arr) {
int g=t,ct=0;
while(g) {
if(g&1) ct++;
g>>=1;
}
tu[ct][cnt[ct]++]=t;
}
for(int i=0;i<32;i++) {
sort(tu[i],tu[i]+cnt[i]);
for(int j=0;j<cnt[i];j++) {
res.push_back(tu[i][j]);
}
}
return res;
}
};
762. 二进制表示中质数个计算置位
一个暴力判断素数函数,一个循环统计二进制1的个数的函数,拿下
class Solution {
public:
bool is_prime(int n) {
if(n==1) return false;
for(int i=2;i<=n/i;i++) {
if(n%i==0) return false;
}
return true;
}
int cul(int n) {
int cnt=0;
while(n) {
if(n&1) cnt++;
n>>=1;
}
return cnt;
}
int countPrimeSetBits(int left, int right) {
int ans=0;
for(int i=left;i<=right;i++) {
if(is_prime(cul(i))) ans++;
}
return ans;
}
};
231. 2 的幂
class Solution {
public:
bool isPowerOfTwo(int n) {
if(n<=0) return false;
return !(n&(n-1));
}
};