位运算符
- 与&
- 或|
- 异或^
- 左移运算符m<<n:左移n位,最左边的n位将被丢弃,同时在右边补n个0
例如:00001010<<2=00101000 - 右移运算符:m>>n:右移n位,最右边的n位将被丢弃。但是左边补齐的时候分两种情况:如果是一个无符号数值,补0;如果是一个有符号数值,用符号位去补,即正数补0,负数补1
例如:有符号数00001010>>2=00000010
有符号数10001010>>3=11110001
相关题目:
1.二进制中1的个数
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
方法一:
最常想到的方法但是可能引起死循环
判断整数最右边一位是不是1,然后不断地右移判断倒数第二位,判断方法是通过与1做&
class Solution {
public:
int NumberOf1(int n) {
int count=0;
while(n)
{
if(n&1)
count++;
n=n>>1;
}
return count;
}
};
但是如果输入一个负数,右移时会在左边补1,一直右移会引起死循环
方法二:
首先把n和1做与运算,判断n的最低位是不是1,接着把1左移一位得到2,再与n做与运算,判断n的次低位是不是1
class Solution {
public:
int NumberOf1(int n) {
int count=0;
unsigned int flag=1;
while(flag)
{
if(n&flag)
count++;
flag=flag<<1;
}
return count;
}
};
循环的次数等于整数二进制的位数,32位的整数就需要循环32次
方法三:
整数中有几个1就需要循环几次
把一个整数减去1,再和原整数做与运算,就会把该整数最右边的1变成0,那么一个整数的二进制表示中有多少个1就可以进行多少次这样的操作。
例如1100,减去1得到1011,做与得到1000
1000再减去1得到0111,做与得到0000
class Solution {
public:
int NumberOf1(int n) {
int count=0;
while(n)
{
count++;
n=n&(n-1);
}
return count;
}
};
2.用一条语句判断一个整数是不是2的整数次方
一个整数如果是2的整数次方,那么它的二进制表示中有且只有一位是1,而其他所有位都是0。把这个整数减去1之后再和它自己做与运算,这个整数中唯一的1就会变成0.
#include<iostream>
using namespace std;
int main()
{
int n;
cin>>n;
if(((n-1)&n)==0)
cout<<"true";
else
cout<<"false";
return 0;
}
3.不用加减乘除做加法
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
class Solution {
public:
int Add(int num1, int num2)
{
int sum=0,carry=0;
while(num2)
{
sum=num1^num2;
carry=(num1&num2)<<1;
num1=sum;
num2=carry;
}
return num1;;
}
};
4.不使用新的变量,交换两个变量的值
基于加减法
a=a+b;
b=a-b;
a=a-b;
基于异或:
a=a^b;
b=a^b;
a=a^b;
5.比特位计数
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
示例 1:
输入: 2
输出: [0,1,1]
示例 2:
输入: 5
输出: [0,1,1,2,1,2]
class Solution {
public:
vector<int> countBits(int num) {
vector<int> res(num+1,0);
for(int i=1;i<=num;i++)
{
res[i]=res[i&(i-1)]+1;
}
return res;
}
};