文章目录
- 前言
- 一、位运算几种模型:
- 1.1 基础的位运算: << >> ~ & | ^
- 1.2 几种模型:
- 1.3 模型练习
- 二、位运算示例:
- 2.1 判定字符是否唯⼀
- 2.2 丢失的数字
- 2.3 两整数之和
- 2.4 只出现⼀次的数字 II
- 2.5 消失的两个数字
前言
👧个人主页:@小沈YO.
😚小编介绍:欢迎来到我的乱七八糟小星球🌝
📋专栏:优选算法
🔑本章内容:位运算
记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~
一、位运算几种模型:
1.1 基础的位运算: << >> ~ & | ^
1.2 几种模型:
- 给一个数n确定它的二进制表示中的第x位是0还是1 ===> (n>>x)&1
- 将一个数n的二进制表示的第x位修改为1 ===> n|=(1<<x)
- 将一个数n的二进制表示的第x位修改成0 ===> n&=(~(1<<x))
- 位图思想 ===> 一个数字的二进制的每一位可以存储0或者1来表示模拟实现哈希
- 提取一个数n的二进制表示中最右侧的1 ===> n&(~n) (-n《= =》 n取反+1)
- 干掉一个数n的二进制表示中最右侧的1 ===> n&(n-1)
- 异或运算的运算律 ===> (1) a ^ 0 = 0 (2) a ^ a = 0 (3) a ^ b ^ c = a ^ (b ^ c)
1.3 模型练习
- 191. 位1的个数
- 338. 比特位计数
- 461. 汉明距离
- 136. 只出现一次的数字
- 260. 只出现一次的数字 III
二、位运算示例:
2.1 判定字符是否唯⼀
- 题⽬链接:⾯试题 01.01. 判定字符是否唯⼀
- 题⽬描述:
- 解法(位图的思想):
算法思路:
利⽤「位图」的思想,每⼀个「⽐特位」代表⼀个「字符,⼀个 int 类型的变量的 32 位⾜够表⽰所有的⼩写字⺟。⽐特位⾥⾯如果是 0 ,表⽰这个字符没有出现过。⽐特位⾥⾯的值是 1 ,表⽰该字符出现过。那么我们就可以⽤⼀个「整数」来充当「哈希表」。 - C++代码
class Solution {
public:
bool isUnique(string astr)
{
if(astr.size() > 26) return false;
int ret=0;
for(auto&e:astr)
{
if((ret>>(e-'a')&1)==1)return false;
else
ret|=(1<<(e-'a'));
}
return true;
}
};
2.2 丢失的数字
-
题⽬链接:268. 丢失的数字
-
题⽬描述:
-
解法(位运算):
算法思路:
设数组的⼤⼩为 n ,那么缺失之前的数就是 [0, n] ,数组中是在 [0, n] 中缺失⼀个数形成的序列。
如果我们把数组中的所有数,以及 [0, n] 中的所有数全部「异或」在⼀起,那么根据「异或」运算的「消消乐」规律,最终的异或结果应该就是缺失的数~ -
C++代码
class Solution {
public:
int missingNumber(vector<int>& nums)
{
int ret=0;
for(int i=0;i<=nums.size();i++)
ret^=i;
for(auto&e:nums)
ret^=e;
return ret;
}
};
2.3 两整数之和
- 题⽬链接:371. 两整数之和
- 题⽬描述:
- 解法(位运算):
算法思路:
◦ 异或 ^ 运算本质是「⽆进位加法」;
◦ 按位与 & 操作能够得到「进位」; 比如3&5 = = => 011&101= = =>001也就是同为1的时候相加会有进位但是这个进位要进给前一个位置所以还要右移1位
◦ 然后⼀直循环进⾏,直到「进位」变成 0 为⽌ - C++代码
class Solution {
public:
int getSum(int a, int b)
{
while(b)
{
int x=a^b;
unsigned int y=(unsigned int)(a&b)<<1;
a=x;
b=y;
}
return a;
}
};
2.4 只出现⼀次的数字 II
- 题⽬链接:137. 只出现⼀次的数字 II
- 题⽬描述:
- 解法(⽐特位计数):
算法思路:
设要找的数位 ret 。
由于整个数组中,需要找的元素只出现了「⼀次」,其余的数都出现的「三次」,因此我们可以根据所有数的「某⼀个⽐特位」的总和 %3 的结果,快速定位到 ret 的「⼀个⽐特位上」的值是 0 还是 1 。 这样,我们通过 ret 的每⼀个⽐特位上的值,就可以将 ret 给还原出来。 - C++代码
class Solution {
public:
int singleNumber(vector<int>& nums)
{
int ret=0;
for(int i=0;i<32;i++)
{
int sum=0;
for(auto&e:nums)
{
if((e>>i)&1==1)sum++;
}
sum%=3;
if(sum==1)ret|=(1<<i);
}
return ret;
}
};
2.5 消失的两个数字
- 题⽬链接:⾯试题 17.19. 消失的两个数字
- 题⽬描述:
- 解法(位运算):
算法思路:
本题就是 268. 丢失的数字 + 260. 只出现⼀次的数字 III 组合起来的题。 先将数组中的数和 [1, n + 2] 区间内的所有数「异或」在⼀起,问题就变成了:有两个数出现了「⼀次」,其余所有的数出现了「两次」。进⽽变成了 260. 只出现⼀次的数字 III 这道题。 - C++代码
class Solution {
public:
vector<int> missingTwo(vector<int>& nums)
{
int n=nums.size()+2;
int ret=0;
for(int i=1;i<=n;i++)
ret^=i;
for(auto&e:nums)ret^=e;
int l=0;
for(int i=0;i<32;i++)
{
if(((ret>>i)&1)==1)
{
l=i;
break;
}
}
int a=0,b=0;
for(auto&e:nums)
{
if(((e>>l)&1)==1)a^=e;
else b^=e;
}
for(int i=1;i<=n;i++)
{
if(((i>>l)&1)==1)a^=i;
else b^=i;
}
return {a,b};
}
};