1几个常见的位运算
1.对于数字n,判断n的二进制表示中的第x位是0还是1
(n>>x)&1
例如 n为 0000 1111 1111 1111 1111 1111 1111 0100 x为2 注意这里的位数是从0开始到31的
n>>3为 0000 0001 1111 1111 1111 1111 1111 1101
(n>>x)&1为 0000 0000 0000 0000 0000 0000 0000 0001
2将第x位改为1
n|(1<<x)
3将第x为改为0
n&(~(1<<x))
4提取最右侧1
例如:
n为 1001 0101 1110 0000
-n为n取反然后加一
~n 0110 1010 0001 1111
~n+1 0110 1010 0010 0000
n&(-n) 可以发现 第x位后的值都是不一样的
n&(-n)
5干掉最右侧1
例如
n为 1001 0101 1110 0000
n-1为 1001 0101 1101 1111
n&(n-1)1001 0101 1100 0000
n&(n-1)
6异或运算规律
1.a^0=a
2.a^a=0
3.(a^b)^c=a^(b^c)
2.例题
1.位1的个数
每次循环用n&(-n)判断是否还有1,循环内用n&(n-1)来去除1
class Solution {
public:
int hammingWeight(int n) {
int count=0;
while(n&(-n))
{
n=n&(n-1);
count++;
}
return count;
}
};
2.比特位计数
找二进制位有多少1
class Solution {
public:
int _countbit(int n)
{
int i=0;
while(n&(-n))
{
i++;
n=n&(n-1);
}
return i;
}
vector<int> countBits(int n) {
vector <int>arr(n+1);
for(int i=0;i<=n;i++)
{
arr[i]=_countbit(i);
}
return arr;
}
};
3.汉明距离
找第x位是0还是1
注意运算优先级 (括号)
class Solution {
public:
int hammingDistance(int x, int y) {
int ret=0;
for(int i=0;i<32;i++)
{
if(((x>>i)&1)&&!((y>>i)&1))
ret++;
else if(!((x>>i)&1)&&((y>>i)&1))
ret++;
else
;
}
return ret;
}
};
4只出现一次的数字
异或的运用
class Solution {
public:
int singleNumber(vector<int>& nums) {
int sum=0;
for(auto i:nums)
{
sum^=i;
}
return sum;
}
};
5只出现一次的数字 III
注意点:溢出问题
数据的范围为-2^31<=nums[i]<=2^31-1
当为-2^31时,补码形式为1000 0000 0000 0000 0000 0000 0000 0000
对它取负号变为全零了 溢出了
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
int XOR = 0;
for(auto i:nums)
{ XOR^=i;
}
int lowbit =XOR==INT_MIN?XOR:XOR&(-XOR);
int a=0,b=0;
for(int i=0;i<nums.size();i++)
{
if(lowbit&nums[i])
a^=nums[i];
else
b^=nums[i];
}
return {a,b};
}
};
6. 判定字符是否唯一
法一 :用大小为26的hash数组
法二 用位图思想 同等hash表
int变量有32位bit 用0位置bit位表示a 1位置bit位表示b
0表示字符没有出现,1位置表示字符出现过 作用同等hash表
法一
class Solution {
public:
bool isUnique(string astr) {
int arr[27]={0};
for(int i=0;i<astr.size();i++)
{
if(arr[astr[i]-'a']==0)
arr[astr[i]-'a']++;
else
return false;
}
return true;
}
};
法二
class Solution {
public:
bool isUnique(string astr) {
int bit=0;
for(int i=0;i<astr.size();i++)
{
if(((bit>>(astr[i]-'a'))&1)==1)
return false;
else
bit=bit|(1<<astr[i]-'a');
}
return true;
}
};
7丢失的数字
异或的性质 先所有元素异或一遍 再异或1到n
class Solution {
public:
int missingNumber(vector<int>& nums) {
int XOR=0;
for(auto i:nums)
XOR^=i;
for(int i=0;i<=nums.size();i++)
XOR^=i;
return XOR;
}
};
8消失的两个数字
将数组所有元素和1到n一起异或,此时异或的结果是消失的两个数字的异或。就可以转换为 只出现一次的数字Ⅲ
如果是通过n&(n-1)获得的最有侧1 这种就不是判断n&1 是都等于1或0了 而是判断是否是0或不是0
class Solution {
public:
vector<int> missingTwo(vector<int>& nums) {
int XOR=0;
for(auto num:nums)
XOR^=num;
for(int i=1;i<=nums.size()+2;i++)
XOR^=i;
int lowbit=XOR==INT_MIN?XOR:XOR&(-XOR);
int a=0;
int b=0;
for(int i=1;i<=nums.size()+2;i++)
{
if(lowbit&i)//这种就不是判断是都等于1或0了 而是判断是否是0或不是0
a^=i;
else
b^=i;
}
for(auto num:nums)
{ if(lowbit&num)
a^=num;
else
b^=num;
}
return {a,b};
}
};
9只出现一次的数字 II
这题有3个相同的数*n+只出现一次的数,3个相同的数*n的第i位bit的和只能是3的倍数,则sum%3就是只出现一次的数(0或1)
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ans=0;
for(int i=0;i<32;i++)
{
int sum=0;
for(auto num:nums)
{
sum+=(num>>i)&1;
}
if(sum%3)
ans|=(1<<i);
else
ans&=(~(1<<i));
}
return ans;
}
};