一、基础知识
1.基础位运算
<< 左移操作符 &按位与 有0就是0
>>右移操作符 | 按位或 有1就是1
~按位取反 ^异或 相同为1,相异为0 / 无进位相加
例如 1 0 1 1 0 1 ^
1 1 0 1 1 0
结果为 0 1 1 0 1 1,无进位相加就是1 + 0 = 0,1+1 = 0,但是不会向高位进位
2.给一个数n,确定它的二进制表示中的第x位是0还是1
我们规定从右往左,的位数为第0,1,2,3,4,5.....31位
这样右移动的距离等于它的位数
(n >> x) & 1 -> 0 ------ 0
1 ------ 1
3.将一个数n的二进制表示的第x位修改成1
n = n | (1 << x)
4.将一个数n的二进制表示的第n位修改成0
n = n &(~(1 << x))
5.位图的思想
每个比特位0或者1的数值表示一种状态
6.提取一个数n,二进制表示中最右侧的1
lowbit = n & -n(取反加一即变为负)
7.将一个数n二进制表示中最右侧的1抹去
n = n & (n - 1)
8.位运算的优先级
能加括号就加括号
9.异或 ^,运算的运算律
1.a ^ a = 0
2.a ^ 0 = a
3.a ^ b ^ c = a ^ (b ^ c)
二、基础题目示例
1.位1的个数
. - 力扣(LeetCode)
class Solution {
public:
int hammingWeight(int i) {
int ret = 0;
int n = 32;
while(n > 0)
{
if((i & 1) == 1)ret++;
i = i >> 1;
n--;
}
return ret;
}
};
将要判断的数每次按位与1,若为1则此位为1,然后再右移一位
2.比特位计数
. - 力扣(LeetCode)
class Solution {
public:
int Add(int i)
{
int ret = 0;
int n = 32;
while(n > 0)
{
if((i & 1) == 1)ret++;
i = i >> 1;
n--;
}
return ret;
}
vector<int> countBits(int n) {
vector<int>ret(n+1,0);
for(int i = 0; i <= n;i++)
{
ret[i] = Add(i);
}
return ret;
}
};
原理同上,只是多了一个循环
3.汉明距离
. - 力扣(LeetCode)
class Solution {
public:
int hammingDistance(int x, int y) {
int n = 32;
int ret = 0;
while(n>0)
{
if((x & 1) != (y & 1))ret++;
x = x >> 1;
y = y >> 1;
n--;
}
return ret;
}
};
分别用 &1 来判断两个数最低位是0还是1,对两个数进行比较,然后分别不断右移这两个数
4.只出现一次的数字
. - 力扣(LeetCode)
利用异或的性质即可
class Solution {
public:
int singleNumber(vector<int>& nums)
{
int val = 0;
for(auto ch:nums)
{
val ^= ch;
}
return val;
}
};
5.只出现一次的数字3
. - 力扣(LeetCode)
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
long long n = 0;
for(auto ch: nums)
{
n ^= ch;
}
long long mask = n &(-n);
mask = (int)mask;
vector<int>ret(2,0);
for(auto ch: nums)
{
if((ch & mask) == mask)ret[0] ^= ch;
else ret[1] ^= ch;
}
return ret;
}
};
我们先将所有值异或,这个过程会将相同的数都消去,最后得到两个不同的数a,b异或的结果。
这个数为1的位置,是两个数上值不同的位置。为了方便,我们取出最右侧的1。
a,b两个数中,一个数的该位置为1,一个数为0.
而待分开的数的该位置也一定为1或0.因此我们将全部数分为两组
a,xx yy zz b,mm,nn,oo
这样即可分别取出单独的数