文章目录
- 上期回顾
- 位运算
-
- 位运算简介及常用性质总结
-
- 基础位运算
- 对于一个数n的第X位
- 一个数二进制表示里最右边的1
- [^ 的性质(交换律,结合律,相同 ^ 为0)](#^ 的性质(交换律,结合律,相同 ^ 为0))
- 本章算法题的简单总结(建议最后看)
- 1,判定字符是否唯一⭐️
- 解题思路
- 2,丢失的数字⭐️
- 解题思路
- 3,两整数之和⭐️⭐️⭐️
- 解题思路
- [4,只出现一次的数字 II⭐️⭐️⭐️](#4,只出现一次的数字 II⭐️⭐️⭐️)
- 解题思路
- 5,消失的两个数字⭐️⭐️⭐️⭐️
- 解题思路
- 下期预告
- 结语

◆ 博主名称:此生决int
大家好,欢迎来到我的博客~
⭐ 个人专栏:快速复习系列
⭐ 热门专栏:蓝桥杯/ACM & 面试算法入门到进阶
上期回顾
上期我们主要介绍了前缀和
文章概要
本文主要介绍了位运算及相关性质,然后通过五道算法题来巩固对位运算的理解!
位运算
位运算简介及常用性质总结
基础位运算
1,按位与:& 有0则为0
2,按位或:| 有1则为1
3,按位异或:^ 同为0,异为1
4,按位取反:~ 1变0,0变1
对于一个数n的第X位
获取它是0还是1(n&=(1<<x))
因为是获取嘛,所以,其他位是什么就不重要了,最后的结果肯定是想要得到00000...010...000这样的效果的,所以,我们要选有0就为0的&(按位与)。
修改它为1(n|=(1<<x))
修改就要保证其他位不变,又要改为1,所以,有用有1就为1的 | (按位或),那么我们就要按位或一个这样的数000...010...000,让1左移x位即可.
修改它为0(n&=(~(1<<x)))
要改为0,就只能用(有0则0)&,然后又要保证其他位不变,所以要&上一个111...101...111这样的数,让1左移x位再取反即可。
一个数二进制表示里最右边的1
提取它(n&(--n))
对于-n,--n的效果是让一个数的二进制的最右边的1左边的数全部变成相反,(不包括那个1)
所以,让n&--n,那个1,右边全是0,还是0,左边一定两两相反,所以&后就是0啦。
干掉它(n&n--1)
对于n-1,n--1他可以把那个1的右边全变成相反,包括那个1,所以&完之后就全变成0啦。
^ 的性质(交换律,结合律,相同 ^ 为0)
1,a^0=a
2,a^a=0
3,a ^ b ^ c=a ^ (b ^ c)

本章算法题的简单总结(建议最后看)
1,判定字符是否唯一⭐️(位图的思想)
2,丢失的数字⭐️(按位异或的性质)
3,两整数之和⭐️⭐️⭐️(加法的模拟加位运算基础性质)
4,只出现一次的数字 II⭐️⭐️⭐️(思维+比特位的控制)
5,消失的两个数字⭐️⭐️⭐️⭐️
1,判定字符是否唯一⭐️
题目链接:
解题思路
1,位图的思想
1,首先肯定想到哈希表,然后,都是小写字母,所以,可以用数组来存,再优化,可以用一个int来存(位图)
由于字符串只包含小写字母,因此可以使用一个 int 的二进制位表示字符是否出现过。第 i 位为 1 表示字符已经出现,再次出现则返回 false。
解题代码
cpp
class Solution {
public:
bool isUnique(string astr) {
//哈希表->数组代替->位图
//n 的二进制位表示字符是否出现
int n=0;
for(auto it:astr)
{
//计算当前字符对应哪一位
int i=it-'a';
//这一位已经是 1
//说明字符重复出现
if(n&(1<<i))
return false;
else
//把这一位改成 1
n|=(1<<i);
}
return true;
}
};
没懂?看看大神的解题代码!!
大神解题代码
cpp
class Solution {
public:
bool isUnique(string astr) {
//一个 int 有 32 位
//可以表示 26 个小写字母是否出现
int mask=0;
for(auto c:astr)
{
//得到当前字符对应的二进制位
int bit=1<<(c-'a');
//这一位已经出现过
if(mask&bit)
return false;
//标记当前字符出现
mask|=bit;
}
return true;
}
};
2,丢失的数字⭐️
题目链接:
解题思路
异或的性质
利用异或性质:相同数字异或两次会变成 0。将数组中的元素和 0~n 全部异或,最后剩下的就是缺失的数字。
解题代码
cpp
class Solution {
public:
int missingNumber(vector<int>& nums) {
//ret 保存异或结果
int ret=0;
for(int i=0;i<nums.size();i++)
{
//异或数组元素
ret^=nums[i];
//异或下标
ret^=i;
}
//最后再异或 n
return ret^nums.size();
}
};
没懂?看看大神的解题代码!!
大神解题代码
cpp
class Solution {
public:
int missingNumber(vector<int>& nums) {
//先把答案初始化为 n
int ret=nums.size();
for(int i=0;i<nums.size();i++)
//同时异或下标和数组元素
ret^=i^nums[i];
return ret;
}
};
3,两整数之和⭐️⭐️⭐️
题目链接:
解题思路
利用位运算模拟加法。a^b 可以得到不进位的结果,(a&b)<<1 可以得到进位结果。不断循环相加,直到没有进位为止。
解题代码
cpp
class Solution {
public:
int getSum(int a, int b) {
//模拟加法
//a^b 得到不进位结果
//(a&b)<<1 得到进位结果
//不断相加直到没有进位
while(b)
{
//不进位的和
int x=a^b;
//进位
int y=(a&b)<<1;
a=x;
b=y;
}
return a;
}
};
没懂?看看大神的解题代码!!
大神解题代码
cpp
class Solution {
public:
int getSum(int a, int b) {
//b 表示进位
while(b)
{
//carry 保存进位
unsigned carry=(unsigned)(a&b)<<1;
//计算不进位结果
a^=b;
//更新进位
b=carry;
}
return a;
}
};
4,只出现一次的数字 II⭐️⭐️⭐️
题目链接:
解题思路
由于除了一个数字只出现一次,其余数字都出现三次,因此统计每一比特位上 1 出现的次数,再对 3 取模。最后剩下的位就是只出现一次数字的二进制位。
解题代码
cpp
class Solution {
public:
int singleNumber(vector<int>& nums) {
//arr[i] 表示第 i 位 1 出现的次数
int arr[32]={0};
//统计每一位 1 的个数
for(int i=0;i<nums.size();i++)
{
for(int j=0;j<32;j++)
{
//对 3 取模
arr[j]=(arr[j]+((nums[i]>>j)&1))%3;
}
}
int ret=0;
//a 表示当前位权值
long long a=1;
//还原答案
for(int i=0;i<32;i++)
{
//这一位存在
if(arr[i])
ret+=a;
a*=2;
}
return ret;
}
};
没懂?看看大神的解题代码!!
大神解题代码
cpp
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ret=0;
//枚举每一位
for(int i=0;i<32;i++)
{
int count=0;
//统计这一位 1 的个数
for(auto x:nums)
count+=(x>>i)&1;
//不能被 3 整除
//说明答案这一位是 1
if(count%3)
ret|=(1<<i);
}
return ret;
}
};
5,消失的两个数字⭐️⭐️⭐️⭐️
题目链接:
解题思路
先将数组元素和 1~n 全部异或,得到缺失的两个数字异或结果。由于这两个数字不同,因此异或结果某一位一定为 1 。根据这一位是否为 1 分组,分为与a一样或与b一样,再分别异或即可得到两个缺失数字。
解题代码
cpp
class Solution {
public:
vector<int> missingTwo(vector<int>& nums) {
//tmp 为两个缺失数字异或结果
int tmp=0;
//异或数组元素
for(auto it:nums)
tmp^=it;
//异或 1~n
for(int i=1;i<=nums.size()+2;i++)
tmp^=i;
//找到第一个不同位
int diff=0;
while(1)
{
//这一位为 1
if((tmp>>diff)&1)
break;
else
diff++;
}
int a=0,b=0;
//按 diff 位是否为 1 分组
for(auto it:nums)
{
if((it>>diff)&1)
a^=it;
else
b^=it;
}
//继续异或 1~n
for(int i=1;i<=nums.size()+2;i++)
{
if((i>>diff)&1)
a^=i;
else
b^=i;
}
return {a,b};
}
};
没懂?看看大神的解题代码!!
大神解题代码
cpp
class Solution {
public:
vector<int> missingTwo(vector<int>& nums) {
//xorSum 为两个缺失数字异或结果
int xorSum=0;
for(auto x:nums)
xorSum^=x;
for(int i=1;i<=nums.size()+2;i++)
xorSum^=i;
//lowbit 取出最低位的 1
int lowbit=xorSum&-xorSum;
int a=0,b=0;
//按 lowbit 分组
for(auto x:nums)
{
if(x&lowbit)
a^=x;
else
b^=x;
}
//继续异或 1~n
for(int i=1;i<=nums.size()+2;i++)
{
if(i&lowbit)
a^=i;
else
b^=i;
}
return {a,b};
}
};
下期预告
结语
本期内容就到这里啦,欢迎大家在评论区一起交流讨论
如果你也在为蓝桥杯/ACM备赛头疼,或是准备算法面试找不到系统学习路径,欢迎订阅我的「算法从入门到精通」专栏!
这里没有枯燥的理论堆砌,只有完整的算法学习路线 ,
搭配精选梯度习题+清晰思路解析,帮你把每个算法学透、练熟。包教包会的!
我们一起在算法路上稳步进阶!




